From bb6571f426ee190a7fb19788924c2ea82f93e540 Mon Sep 17 00:00:00 2001 From: rbygrave Date: Thu, 4 Dec 2014 01:47:11 +1300 Subject: [PATCH] javadoc update, eol characters --- .../java/com/avaje/ebean/EbeanServer.java | 3507 +++++++++-------- .../avaje/ebean/annotation/Transactional.java | 207 +- 2 files changed, 1874 insertions(+), 1840 deletions(-) diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java index f78d82727..cf855e281 100644 --- a/src/main/java/com/avaje/ebean/EbeanServer.java +++ b/src/main/java/com/avaje/ebean/EbeanServer.java @@ -1,1737 +1,1770 @@ -package com.avaje.ebean; - -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.persistence.OptimisticLockException; -import javax.persistence.PersistenceException; - -import com.avaje.ebean.annotation.CacheStrategy; -import com.avaje.ebean.cache.ServerCacheManager; -import com.avaje.ebean.config.ServerConfig; -import com.avaje.ebean.meta.MetaInfoManager; -import com.avaje.ebean.text.csv.CsvReader; -import com.avaje.ebean.text.json.JsonContext; - -/** - * Provides the API for fetching and saving beans to a particular DataSource. - *

- * Registration with the Ebean Singleton:
- * When a EbeanServer is constructed it can be registered with the Ebean - * singleton (see {@link ServerConfig#setRegister(boolean)}). The Ebean - * singleton is essentially a map of EbeanServer's that have been registered - * with it. The EbeanServer can then be retrieved later via - * {@link Ebean#getServer(String)}. - *

- *

- * The 'default' EbeanServer
- * One EbeanServer can be designated as the 'default' or 'primary' EbeanServer - * (see {@link ServerConfig#setDefaultServer(boolean)}. Many methods on Ebean - * such as {@link Ebean#find(Class)} etc are actually just a convenient way to - * call methods on the 'default/primary' EbeanServer. This is handy for - * applications that use a single DataSource. - *

- * There is one EbeanServer per Database (javax.sql.DataSource). One EbeanServer - * is referred to as the 'default' server and that is the one that - * Ebean methods such as {@link Ebean#find(Class)} use. - *

- *

- * Constructing a EbeanServer
- * EbeanServer's are constructed by the EbeanServerFactory. They can be created - * programmatically via {@link EbeanServerFactory#create(ServerConfig)} or they - * can be automatically constructed on demand using configuration information in - * the ebean.properties file. - *

- *

- * Example: Get a EbeanServer - *

- * - *
{@code
- * // Get access to the Human Resources EbeanServer/Database
- * EbeanServer hrServer = Ebean.getServer("HR");
- * 
- * 
- * // fetch contact 3 from the HR database Contact contact =
- * hrServer.find(Contact.class, new Integer(3));
- * 
- * contact.setStatus("INACTIVE"); ...
- * 
- * // save the contact back to the HR database hrServer.save(contact);
- * }
- * - *

- * EbeanServer has more API than Ebean
- * EbeanServer provides additional API compared with Ebean. For example it - * provides more control over the use of Transactions that is not available in - * the Ebean API. - *

- *

- * External Transactions: If you wanted to use transactions created - * externally to eBean then EbeanServer provides additional methods where you - * can explicitly pass a transaction (that can be created externally). - *

- *

- * Bypass ThreadLocal Mechanism: If you want to bypass the built in - * ThreadLocal transaction management you can use the createTransaction() - * method. Example: a single thread requires more than one transaction. - *

- * - * @see Ebean - * @see EbeanServerFactory - * @see ServerConfig - */ -public interface EbeanServer { - - /** - * Shutdown the EbeanServer programmatically. - *

- * This method is not normally required. Ebean registers a shutdown hook and shuts down cleanly. - *

- *

- * If the under underlying DataSource is the Ebean implementation then you - * also have the option of shutting down the DataSource and deregistering the - * JDBC driver. - *

- * - * @param shutdownDataSource - * if true then shutdown the underlying DataSource if it is the EbeanORM - * DataSource implementation. - * @param deregisterDriver - * if true then deregister the JDBC driver if it is the EbeanORM - * DataSource implementation. - */ - public void shutdown(boolean shutdownDataSource, boolean deregisterDriver); - - /** - * Return the AdminAutofetch which is used to control and configure the - * Autofetch service at runtime. - */ - public AdminAutofetch getAdminAutofetch(); - - /** - * Return the name. This is used with {@link Ebean#getServer(String)} to get a - * EbeanServer that was registered with the Ebean singleton. - */ - public String getName(); - - /** - * Return the ExpressionFactory for this server. - */ - public ExpressionFactory getExpressionFactory(); - - /** - * Return the MetaInfoManager which is used to get meta data from the EbeanServer - * such as query execution statistics. - */ - public MetaInfoManager getMetaInfoManager(); - - /** - * Return the BeanState for a given entity bean. - *

- * This will return null if the bean is not an enhanced entity bean. - *

- */ - public BeanState getBeanState(Object bean); - - /** - * Return the value of the Id property for a given bean. - */ - public Object getBeanId(Object bean); - - /** - * Return a map of the differences between two objects of the same type. - *

- * When null is passed in for b, then the 'OldValues' of a is used for the - * difference comparison. - *

- */ - public Map diff(Object a, Object b); - - /** - * Create a new instance of T that is an EntityBean. - *

- * Generally not expected to be useful (now dynamic subclassing support was removed in - * favour of always using enhancement). - *

- */ - public T createEntityBean(Class type); - - /** - * Create a CsvReader for a given beanType. - */ - public CsvReader createCsvReader(Class beanType); - - /** - * Return a named Query that will have defined fetch paths, predicates etc. - *

- * The query is created from a statement that will be defined in a deployment - * orm xml file or NamedQuery annotations. The query will typically already - * define fetch paths, predicates, order by clauses etc so often you will just - * need to bind required parameters and then execute the query. - *

- * - *
{@code
-   *
-   *   // example
-   *   Query query = ebeanServer.createNamedQuery(Order.class, "new.for.customer");
-   *   query.setParameter("customerId", 23);
-   *   List newOrders = query.findList();
-   *
-   * }
- */ - public Query createNamedQuery(Class beanType, String namedQuery); - - /** - * Create a query using the query language. - *

- * Note that you are allowed to add additional clauses using where() as well - * as use fetch() and setOrderBy() after the query has been created. - *

- *

- * Note that this method signature used to map to named queries and that has - * moved to {@link #createNamedQuery(Class, String)}. - *

- * - *
{@code
-   *  EbeanServer ebeanServer = ... ;
-   *  String q = "find order fetch details where status = :st";
-   *  
-   *  List newOrders
-   *        = ebeanServer.createQuery(Order.class, q)
-   *             .setParameter("st", Order.Status.NEW)
-   *             .findList();
-   * }
- * - * @param query - * the object query - */ - public Query createQuery(Class beanType, String query); - - /** - * Create a query for an entity bean and synonym for {@link #find(Class)}. - * - * @see #find(Class) - */ - public Query createQuery(Class beanType); - - /** - * Create a query for a type of entity bean. - *

- * You can use the methods on the Query object to specify fetch paths, - * predicates, order by, limits etc. - *

- *

- * You then use findList(), findSet(), findMap() and findUnique() to execute - * the query and return the collection or bean. - *

- *

- * Note that a query executed by {@link Query#findList()} - * {@link Query#findSet()} etc will execute against the same EbeanServer from - * which is was created. - *

- * - *
{@code
-   *
-   *   // Find order 2 specifying explicitly the parts of the object graph to
-   *   // eagerly fetch. In this case eagerly fetch the associated customer,
-   *   // details and details.product.name
-   *
-   *   Order order = ebeanServer.find(Order.class)
-   *     .fetch("customer")
-   *     .fetch("details")
-   *     .fetch("detail.product", "name")
-   *     .setId(2)
-   *     .findUnique();
-   *
-   *   // find some new orders ... with firstRow/maxRows
-   *   List orders =
-   *     ebeanServer.find(Order.class)
-   *       .where().eq("status", Order.Status.NEW)
-   *       .setFirstRow(20)
-   *       .setMaxRows(10)
-   *       .findList();
-   *
-   * }
- * - */ - public Query find(Class beanType); - - /** - * Return the next unique identity value for a given bean type. - *

- * This will only work when a IdGenerator is on the bean such as for beans - * that use a DB sequence or UUID. - *

- *

- * For DB's supporting getGeneratedKeys and sequences such as Oracle10 you do - * not need to use this method generally. It is made available for more - * complex cases where it is useful to get an ID prior to some processing. - *

- */ - public Object nextId(Class beanType); - - /** - * Create a filter for sorting and filtering lists of entities locally without - * going back to the database. - *

- * This produces and returns a new list with the sort and filters applied. - *

- *

- * Refer to {@link Filter} for an example of its use. - *

- */ - public Filter filter(Class beanType); - - /** - * Sort the list in memory using the sortByClause which can contain a comma delimited - * list of property names and keywords asc, desc, nullsHigh and nullsLow. - *
    - *
  • asc - ascending order (which is the default)
  • - *
  • desc - Descending order
  • - *
  • nullsHigh - Treat null values as high/large values (which is the - * default)
  • - *
  • nullsLow- Treat null values as low/very small values
  • - *
- *

- * If you leave off any keywords the defaults are ascending order and treating - * nulls as high values. - *

- *

- * Note that the sorting uses a Comparator and Collections.sort(); and does - * not invoke a DB query. - *

- * - *
{@code
-   *
-   *   // find orders and their customers
-   *   List list = ebeanServer.find(Order.class)
-   *     .fetch("customer")
-   *     .orderBy("id")
-   *     .findList();
-   *
-   *   // sort by customer name ascending, then by order shipDate
-   *   // ... then by the order status descending
-   *   ebeanServer.sort(list, "customer.name, shipDate, status desc");
-   *
-   *   // sort by customer name descending (with nulls low)
-   *   // ... then by the order id
-   *   ebeanServer.sort(list, "customer.name desc nullsLow, id");
-   *
-   * }
- * - * @param list - * the list of entity beans - * @param sortByClause - * the properties to sort the list by - */ - public void sort(List list, String sortByClause); - - /** - * Create a named orm update. The update statement is specified via the - * NamedUpdate annotation. - *

- * The orm update differs from the SqlUpdate in that it uses the bean name and - * bean property names rather than table and column names. - *

- *

- * Note that named update statements can be specified in raw sql (with column - * and table names) or using bean name and bean property names. This can be - * specified with the isSql flag. - *

- *

- * Example named updates: - *

- * - *
{@code
-   *   package app.data;
-   *
-   *   import ...
-   *
-   *   @NamedUpdates(value = {
-   *    @NamedUpdate( name = "setTitle",
-   * 	    isSql = false,
-   * 		  notifyCache = false,
-   * 		  update = "update topic set title = :title, postCount = :postCount where id = :id"),
-   * 	  @NamedUpdate( name = "setPostCount",
-   * 		  notifyCache = false,
-   * 		  update = "update f_topic set post_count = :postCount where id = :id"),
-   * 	  @NamedUpdate( name = "incrementPostCount",
-   * 		  notifyCache = false,
-   * 		  isSql = false,
-   * 		  update = "update Topic set postCount = postCount + 1 where id = :id") })
-   *   @Entity
-   *   @Table(name = "f_topic")
-   *   public class Topic { ...
-   *
-   * }
- * - *

- * Example using a named update: - *

- * - *
{@code
-   *
-   *   Update update = ebeanServer.createNamedUpdate(Topic.class, "setPostCount");
-   *   update.setParameter("postCount", 10);
-   *   update.setParameter("id", 3);
-   *
-   *   int rows = update.execute();
-   *   System.out.println("rows updated: " + rows);
-   *
-   * }
- */ - public Update createNamedUpdate(Class beanType, String namedUpdate); - - /** - * Create a orm update where you will supply the insert/update or delete - * statement (rather than using a named one that is already defined using the - * @NamedUpdates annotation). - *

- * The orm update differs from the sql update in that it you can use the bean - * name and bean property names rather than table and column names. - *

- *

- * An example: - *

- * - *
{@code
-   *
-   *   // The bean name and properties - "topic","postCount" and "id"
-   *
-   *   // will be converted into their associated table and column names
-   *   String updStatement = "update topic set postCount = :pc where id = :id";
-   *
-   *   Update update = ebeanServer.createUpdate(Topic.class, updStatement);
-   *
-   *   update.set("pc", 9);
-   *   update.set("id", 3);
-   *
-   *   int rows = update.execute();
-   *   System.out.println("rows updated:" + rows);
-   *
-   * }
- */ - public Update createUpdate(Class beanType, String ormUpdate); - - /** - * Create a SqlQuery for executing native sql - * query statements. - *

- * Note that you can use raw SQL with entity beans, refer to the SqlSelect - * annotation for examples. - *

- */ - public SqlQuery createSqlQuery(String sql); - - /** - * Create a named sql query. - *

- * The query statement will be defined in a deployment orm xml file. - *

- * - * @param namedQuery - * the name of the query - */ - public SqlQuery createNamedSqlQuery(String namedQuery); - - /** - * Create a sql update for executing native dml statements. - *

- * Use this to execute a Insert Update or Delete statement. The statement will - * be native to the database and contain database table and column names. - *

- *

- * See {@link SqlUpdate} for example usage. - *

- *

- * Where possible it would be expected practice to put the statement in a orm - * xml file (named update) and use {@link #createNamedSqlUpdate(String)} . - *

- */ - public SqlUpdate createSqlUpdate(String sql); - - /** - * Create a CallableSql to execute a given stored procedure. - */ - public CallableSql createCallableSql(String callableSql); - - /** - * Create a named sql update. - *

- * The statement (an Insert Update or Delete statement) will be defined in a - * deployment orm xml file. - *

- * - *
{@code
-   *
-   *   // Use a namedQuery
-   *   UpdateSql update = Ebean.createNamedSqlUpdate("update.topic.count");
-   *
-   *   update.setParameter("count", 1);
-   *   update.setParameter("topicId", 50);
-   *
-   *   int modifiedCount = update.execute();
-   *
-   * }
- */ - public SqlUpdate createNamedSqlUpdate(String namedQuery); - - /** - * Register a TransactionCallback on the currently active transaction. - *

- * If there is no currently active transaction then a PersistenceException is thrown. - * - * @param transactionCallback The transaction callback to be registered with the current transaction. - * - * @throws PersistenceException If there is no currently active transaction - */ - public void register(TransactionCallback transactionCallback) throws PersistenceException; - - /** - * Create a new transaction that is not held in TransactionThreadLocal. - *

- * You will want to do this if you want multiple Transactions in a single - * thread or generally use transactions outside of the TransactionThreadLocal - * management. - *

- */ - public Transaction createTransaction(); - - /** - * Create a new transaction additionally specifying the isolation level. - *

- * Note that this transaction is NOT stored in a thread local. - *

- */ - public Transaction createTransaction(TxIsolation isolation); - - /** - * Start a new explicit transaction putting it into a ThreadLocal. - *

- * The transaction is stored in a ThreadLocal variable and typically you only - * need to use the returned Transaction IF you wish to do things like - * use batch mode, change the transaction isolation level, use savepoints or - * log comments to the transaction log. - *

- *

- * Example of using a transaction to span multiple calls to find(), save() - * etc. - *

- * - *
{@code
-   *
-   *   // start a transaction (stored in a ThreadLocal)
-   *   ebeanServer.beginTransaction();
-   *   try {
-   * 	   Order order = ebeanServer.find(Order.class,10); ...
-   *
-   * 	   ebeanServer.save(order);
-   *
-   * 	   ebeanServer.commitTransaction();
-   *
-   *   } finally {
-   * 	   // rollback if we didn't commit
-   * 	   // i.e. an exception occurred before commitTransaction().
-   * 	   ebeanServer.endTransaction();
-   *   }
-   *
-   * }
- * - *

- * If you want to externalise the transaction management then you use - * createTransaction() and pass the transaction around to the various methods on - * EbeanServer yourself. - *

- */ - public Transaction beginTransaction(); - - /** - * Start a transaction additionally specifying the isolation level. - */ - public Transaction beginTransaction(TxIsolation isolation); - - /** - * Returns the current transaction or null if there is no current transaction in scope. - */ - public Transaction currentTransaction(); - - /** - * Commit the current transaction. - */ - public void commitTransaction(); - - /** - * Rollback the current transaction. - */ - public void rollbackTransaction(); - - /** - * If the current transaction has already been committed do nothing otherwise - * rollback the transaction. - *

- * Useful to put in a finally block to ensure the transaction is ended, rather - * than a rollbackTransaction() in each catch block. - *

- *

- * Code example: - * - *

{@code
-   *
-   *   ebeanServer.beginTransaction();
-   *   try {
-   *     // do some fetching and or persisting ...
-   * 
-   *     // commit at the end
-   *     ebeanServer.commitTransaction();
-   * 
-   *   } finally {
-   *     // if commit didn't occur then rollback the transaction
-   *     ebeanServer.endTransaction();
-   *   }
-   *
-   * }
- * - *

- * - */ - public void endTransaction(); - - /** - * Refresh the values of a bean. - *

- * Note that this resets OneToMany and ManyToMany properties so that if they - * are accessed a lazy load will refresh the many property. - *

- */ - public void refresh(Object bean); - - /** - * Refresh a many property of an entity bean. - * - * @param bean - * the entity bean containing the 'many' property - * @param propertyName - * the 'many' property to be refreshed - * - */ - public void refreshMany(Object bean, String propertyName); - - /** - * Find a bean using its unique id. - * - *
{@code
-   *   // Fetch order 1
-   *   Order order = ebeanServer.find(Order.class, 1);
-   * }
- * - *

- * If you want more control over the query then you can use createQuery() and - * Query.findUnique(); - *

- * - *
{@code
-   *   // ... additionally fetching customer, customer shipping address,
-   *   // order details, and the product associated with each order detail.
-   *   // note: only product id and name is fetch (its a "partial object").
-   *   // note: all other objects use "*" and have all their properties fetched.
-   *
-   *   Query query = ebeanServer.find(Order.class)
-   *     .setId(1)
-   *     .fetch("customer")
-   *     .fetch("customer.shippingAddress")
-   *     .fetch("details")
-   *     .query();
-   *
-   *   // fetch associated products but only fetch their product id and name
-   *   query.fetch("details.product", "name");
-   *
-   *
-   *   Order order = query.findUnique();
-   *
-   *   // traverse the object graph...
-   *
-   *   Customer customer = order.getCustomer();
-   *   Address shippingAddress = customer.getShippingAddress();
-   *   List details = order.getDetails();
-   *   OrderDetail detail0 = details.get(0);
-   *   Product product = detail0.getProduct();
-   *   String productName = product.getName();
-   *
-   * }
- * - * @param beanType - * the type of entity bean to fetch - * @param id - * the id value - */ - public T find(Class beanType, Object id); - - /** - * Get a reference object. - *

- * This will not perform a query against the database unless some property other - * that the id property is accessed. - *

- *

- * It is most commonly used to set a 'foreign key' on another bean like: - *

- *
{@code
-   *
-   *   Product product = ebeanServer.getReference(Product.class, 1);
-   *
-   *   OrderDetail orderDetail = new OrderDetail();
-   *   // set the product 'foreign key'
-   *   orderDetail.setProduct(product);
-   *   orderDetail.setQuantity(42);
-   *   ...
-   *
-   *   ebeanServer.save(orderDetail);
-   *
-   *
-   * }
- * - *

Lazy loading characteristics

- *
{@code
-   *
-   *   Product product = ebeanServer.getReference(Product.class, 1);
-   *
-   *   // You can get the id without causing a fetch/lazy load
-   *   Long productId = product.getId();
-   *
-   *   // If you try to get any other property a fetch/lazy loading will occur
-   *   // This will cause a query to execute...
-   *   String name = product.getName();
-   *
-   * }
- * - * @param beanType - * the type of entity bean - * @param id - * the id value - */ - public T getReference(Class beanType, Object id); - - /** - * Return the number of 'top level' or 'root' entities this query should - * return. - * - * @see Query#findRowCount() - * @see com.avaje.ebean.Query#findFutureRowCount() - */ - public int findRowCount(Query query, Transaction transaction); - - /** - * Return the Id values of the query as a List. - * - * @see com.avaje.ebean.Query#findIds() - */ - public List findIds(Query query, Transaction transaction); - - /** - * Return a QueryIterator for the query. - *

- * Generally using {@link #findEach(Query, QueryEachConsumer, Transaction)} or - * {@link #findEachWhile(Query, QueryEachWhileConsumer, Transaction)} is preferred - * to findIterate(). The reason is that those methods automatically take care of - * closing the queryIterator (and the underlying jdbc statement and resultSet). - *

- *

- * This is similar to findEach in that not all the result beans need to be held - * in memory at the same time and as such is good for processing large queries. - *

- * - * @see Query#findEach(QueryEachConsumer) - * @see Query#findEachWhile(QueryEachWhileConsumer) - */ - public QueryIterator findIterate(Query query, Transaction transaction); - - /** - * Execute the query visiting the each bean one at a time. - *

- * Unlike findList() this is suitable for processing a query that will return - * a very large resultSet. The reason is that not all the result beans need to be - * held in memory at the same time and instead processed one at a time. - *

- *

- * Internally this query using a PersistenceContext scoped to each bean (and the - * beans associated object graph). - *

- * - *
{@code
-   *
-   *     ebeanServer.find(Order.class)
-   *       .where().eq("status", Order.Status.NEW)
-   *       .order().asc("id")
-   *       .findEach((Order order) -> {
-   *
-   *         // do something with the order bean
-   *         System.out.println(" -- processing order ... " + order);
-   *       });
-   *
-   * }
- * - * @see Query#findEach(QueryEachConsumer) - * @see Query#findEachWhile(QueryEachWhileConsumer) - */ - public void findEach(Query query, QueryEachConsumer consumer, Transaction transaction); - - /** - * Execute the query visiting the each bean one at a time. - *

- * Compared to findEach() this provides the ability to stop processing the query - * results early by returning false for the QueryEachWhileConsumer. - *

- *

- * Unlike findList() this is suitable for processing a query that will return - * a very large resultSet. The reason is that not all the result beans need to be - * held in memory at the same time and instead processed one at a time. - *

- *

- * Internally this query using a PersistenceContext scoped to each bean (and the - * beans associated object graph). - *

- * - *
{@code
-   *
-   *     ebeanServer.find(Order.class)
-   *       .where().eq("status", Order.Status.NEW)
-   *       .order().asc("id")
-   *       .findEachWhile((Order order) -> {
-   *
-   *         // do something with the order bean
-   *         System.out.println(" -- processing order ... " + order);
-   *
-   *         boolean carryOnProcessing = ...
-   *         return carryOnProcessing;
-   *       });
-   *
-   * }
- * - * @see Query#findEach(QueryEachConsumer) - * @see Query#findEachWhile(QueryEachWhileConsumer) - */ - public void findEachWhile(Query query, QueryEachWhileConsumer consumer, Transaction transaction); - - /** - * Deprecated in favor of #findEachWhile which is functionally exactly the same - * but has a much better name. - *

- * Execute the query visiting the results. This is similar to findIterate in - * that not all the result beans need to be held in memory at the same time - * and as such is go for processing large queries. - *

- * - * @deprecated - */ - public void findVisit(Query query, QueryResultVisitor visitor, Transaction transaction); - - /** - * Execute a query returning a list of beans. - *

- * Generally you are able to use {@link Query#findList()} rather than - * explicitly calling this method. You could use this method if you wish to - * explicitly control the transaction used for the query. - *

- * - *
{@code
-   *
-   * List customers =
-   *     ebeanServer.find(Customer.class)
-   *     .where().ilike("name", "rob%")
-   *     .findList();
-   *
-   * }
- * - * @param - * the type of entity bean to fetch. - * @param query - * the query to execute. - * @param transaction - * the transaction to use (can be null). - * @return the list of fetched beans. - * - * @see Query#findList() - */ - public List findList(Query query, Transaction transaction); - - /** - * Execute find row count query in a background thread. - *

- * This returns a Future object which can be used to cancel, check the - * execution status (isDone etc) and get the value (with or without a - * timeout). - *

- * - * @param query - * the query to execute the row count on - * @param transaction - * the transaction (can be null). - * @return a Future object for the row count query - * - * @see com.avaje.ebean.Query#findFutureRowCount() - */ - public FutureRowCount findFutureRowCount(Query query, Transaction transaction); - - /** - * Execute find Id's query in a background thread. - *

- * This returns a Future object which can be used to cancel, check the - * execution status (isDone etc) and get the value (with or without a - * timeout). - *

- * - * @param query - * the query to execute the fetch Id's on - * @param transaction - * the transaction (can be null). - * @return a Future object for the list of Id's - * - * @see com.avaje.ebean.Query#findFutureIds() - */ - public FutureIds findFutureIds(Query query, Transaction transaction); - - /** - * Execute find list query in a background thread returning a FutureList object. - *

- * This returns a Future object which can be used to cancel, check the - * execution status (isDone etc) and get the value (with or without a timeout). - *

- * This query will execute in it's own PersistenceContext and using its own transaction. - * What that means is that it will not share any bean instances with other queries. - * - * - * @param query - * the query to execute in the background - * @param transaction - * the transaction (can be null). - * @return a Future object for the list result of the query - * - * @see Query#findFutureList() - */ - public FutureList findFutureList(Query query, Transaction transaction); - - /** - * Execute find list SQL query in a background thread. - *

- * This returns a Future object which can be used to cancel, check the - * execution status (isDone etc) and get the value (with or without a - * timeout). - *

- * - * @param query - * the query to execute in the background - * @param transaction - * the transaction (can be null). - * @return a Future object for the list result of the query - */ - public SqlFutureList findFutureList(SqlQuery query, Transaction transaction); - - /** - * Return a PagedList for this query. - *

- * The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and - * {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to - * {@link Query#findFutureRowCount()} to determine total row count, total page count etc. - *

- *

- * Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on - * the query. This translates into SQL that uses limit offset, rownum or row_number - * function to limit the result set. - *

- * - * @param pageIndex - * The zero based index of the page. - * @param pageSize - * The number of beans to return per page. - * @return The PagedList - * - * @see Query#findPagedList(int, int) - */ - public PagedList findPagedList(Query query, Transaction transaction, int pageIndex, int pageSize); - - /** - * Execute the query returning a set of entity beans. - *

- * Generally you are able to use {@link Query#findSet()} rather than - * explicitly calling this method. You could use this method if you wish to - * explicitly control the transaction used for the query. - *

- * - *
{@code
-   *
-   * Set customers =
-   *     ebeanServer.find(Customer.class)
-   *     .where().ilike("name", "rob%")
-   *     .findSet();
-   *
-   * }
- * - * @param - * the type of entity bean to fetch. - * @param query - * the query to execute - * @param transaction - * the transaction to use (can be null). - * @return the set of fetched beans. - * - * @see Query#findSet() - */ - public Set findSet(Query query, Transaction transaction); - - /** - * Execute the query returning the entity beans in a Map. - *

- * Generally you are able to use {@link Query#findMap()} rather than - * explicitly calling this method. You could use this method if you wish to - * explicitly control the transaction used for the query. - *

- * - * @param - * the type of entity bean to fetch. - * @param query - * the query to execute. - * @param transaction - * the transaction to use (can be null). - * @return the map of fetched beans. - * - * @see Query#findMap() - */ - public Map findMap(Query query, Transaction transaction); - - /** - * Execute the query returning at most one entity bean. This will throw a - * PersistenceException if the query finds more than one result. - *

- * Generally you are able to use {@link Query#findUnique()} rather than - * explicitly calling this method. You could use this method if you wish to - * explicitly control the transaction used for the query. - *

- * - * @param - * the type of entity bean to fetch. - * @param query - * the query to execute. - * @param transaction - * the transaction to use (can be null). - * @return the list of fetched beans. - * - * @see Query#findUnique() - */ - public T findUnique(Query query, Transaction transaction); - - /** - * Execute the sql query returning a list of MapBean. - *

- * Generally you are able to use {@link SqlQuery#findList()} rather than - * explicitly calling this method. You could use this method if you wish to - * explicitly control the transaction used for the query. - *

- * - * @param query - * the query to execute. - * @param transaction - * the transaction to use (can be null). - * @return the list of fetched MapBean. - * - * @see SqlQuery#findList() - */ - public List findList(SqlQuery query, Transaction transaction); - - /** - * Execute the sql query returning a set of MapBean. - *

- * Generally you are able to use {@link SqlQuery#findSet()} rather than - * explicitly calling this method. You could use this method if you wish to - * explicitly control the transaction used for the query. - *

- * - * @param query - * the query to execute. - * @param transaction - * the transaction to use (can be null). - * @return the set of fetched MapBean. - * - * @see SqlQuery#findSet() - */ - public Set findSet(SqlQuery query, Transaction transaction); - - /** - * Execute the sql query returning a map of MapBean. - *

- * Generally you are able to use {@link SqlQuery#findMap()} rather than - * explicitly calling this method. You could use this method if you wish to - * explicitly control the transaction used for the query. - *

- * - * @param query - * the query to execute. - * @param transaction - * the transaction to use (can be null). - * @return the set of fetched MapBean. - * - * @see SqlQuery#findMap() - */ - public Map findMap(SqlQuery query, Transaction transaction); - - /** - * Execute the sql query returning a single MapBean or null. - *

- * This will throw a PersistenceException if the query found more than one - * result. - *

- *

- * Generally you are able to use {@link SqlQuery#findUnique()} rather than - * explicitly calling this method. You could use this method if you wish to - * explicitly control the transaction used for the query. - *

- * - * @param query - * the query to execute. - * @param transaction - * the transaction to use (can be null). - * @return the fetched MapBean or null if none was found. - * - * @see SqlQuery#findUnique() - */ - public SqlRow findUnique(SqlQuery query, Transaction transaction); - - /** - * Either Insert or Update the bean depending on its state. - *

- * If there is no current transaction one will be created and committed for - * you automatically. - *

- *

- * Save can cascade along relationships. For this to happen you need to - * specify a cascade of CascadeType.ALL or CascadeType.PERSIST on the - * OneToMany, OneToOne or ManyToMany annotation. - *

- *

- * In this example below the details property has a CascadeType.ALL set so - * saving an order will also save all its details. - *

- * - *
{@code
-   *   public class Order { ...
-   *
-   * 	   @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
-   * 	   @JoinColumn(name="order_id")
-   * 	   List details;
-   * 	   ...
-   *   }
-   * }
- * - *

- * When a save cascades via a OneToMany or ManyToMany Ebean will automatically - * set the 'parent' object to the 'detail' object. In the example below in - * saving the order and cascade saving the order details the 'parent' order - * will be set against each order detail when it is saved. - *

- */ - public void save(Object bean) throws OptimisticLockException; - - /** - * Save all the beans in the iterator. - */ - public int save(Iterator it) throws OptimisticLockException; - - /** - * Save all the beans in the collection. - */ - public int save(Collection beans) throws OptimisticLockException; - - /** - * Delete the bean. - *

- * If there is no current transaction one will be created and committed for - * you automatically. - *

- */ - public void delete(Object bean) throws OptimisticLockException; - - /** - * Delete all the beans from an Iterator. - */ - public int delete(Iterator it) throws OptimisticLockException; - - /** - * Delete all the beans in the collection. - */ - public int delete(Collection c) throws OptimisticLockException; - - /** - * Delete the bean given its type and id. - */ - public int delete(Class beanType, Object id); - - /** - * Delete the bean given its type and id with an explicit transaction. - */ - public int delete(Class beanType, Object id, Transaction transaction); - - /** - * Delete several beans given their type and id values. - */ - public void delete(Class beanType, Collection ids); - - /** - * Delete several beans given their type and id values with an explicit - * transaction. - */ - public void delete(Class beanType, Collection ids, Transaction transaction); - - /** - * Execute a Sql Update Delete or Insert statement. This returns the number of - * rows that where updated, deleted or inserted. If is executed in batch then - * this returns -1. You can get the actual rowCount after commit() from - * updateSql.getRowCount(). - *

- * If you wish to execute a Sql Select natively then you should use the - * FindByNativeSql object. - *

- *

- * Note that the table modification information is automatically deduced and - * you do not need to call the Ebean.externalModification() method when you - * use this method. - *

- *

- * Example: - *

- * - *
{@code
-   *
-   *   // example that uses 'named' parameters
-   *   String s = "UPDATE f_topic set post_count = :count where id = :id"
-   *
-   *   SqlUpdate update = ebeanServer.createSqlUpdate(s);
-   *
-   *   update.setParameter("id", 1);
-   *   update.setParameter("count", 50);
-   *
-   *   int modifiedCount = ebeanServer.execute(update);
-   *
-   *   String msg = "There where " + modifiedCount + "rows updated";
-   *
-   * }
- * - * @param sqlUpdate - * the update sql potentially with bind values - * - * @return the number of rows updated or deleted. -1 if executed in batch. - * - * @see CallableSql - */ - public int execute(SqlUpdate sqlUpdate); - - /** - * Execute a ORM insert update or delete statement using the current - * transaction. - *

- * This returns the number of rows that where inserted, updated or deleted. - *

- */ - public int execute(Update update); - - /** - * Execute a ORM insert update or delete statement with an explicit - * transaction. - */ - public int execute(Update update, Transaction t); - - /** - * For making calls to stored procedures. - *

- * Example: - *

- * - *
{@code
-   *
-   *   String sql = "{call sp_order_modify(?,?,?)}";
-   *
-   *   CallableSql cs = ebeanServer.createCallableSql(sql);
-   *   cs.setParameter(1, 27);
-   *   cs.setParameter(2, "SHIPPED");
-   *   cs.registerOut(3, Types.INTEGER);
-   *
-   *   ebeanServer.execute(cs);
-   *
-   *   // read the out parameter
-   *   Integer returnValue = (Integer) cs.getObject(3);
-   *
-   * }
- * - * @see CallableSql - * @see Ebean#execute(SqlUpdate) - */ - public int execute(CallableSql callableSql); - - /** - * Inform Ebean that tables have been modified externally. These could be the - * result of from calling a stored procedure, other JDBC calls or external - * programs including other frameworks. - *

- * If you use ebeanServer.execute(UpdateSql) then the table modification information - * is automatically deduced and you do not need to call this method yourself. - *

- *

- * This information is used to invalidate objects out of the cache and - * potentially text indexes. This information is also automatically broadcast - * across the cluster. - *

- *

- * If there is a transaction then this information is placed into the current - * transactions event information. When the transaction is committed this - * information is registered (with the transaction manager). If this - * transaction is rolled back then none of the transaction event information - * registers including the information you put in via this method. - *

- *

- * If there is NO current transaction when you call this method then this - * information is registered immediately (with the transaction manager). - *

- * - * @param tableName - * the name of the table that was modified - * @param inserted - * true if rows where inserted into the table - * @param updated - * true if rows on the table where updated - * @param deleted - * true if rows on the table where deleted - */ - public void externalModification(String tableName, boolean inserted, boolean updated, boolean deleted); - - /** - * Find a entity bean with an explicit transaction. - * - * @param - * the type of entity bean to find - * @param beanType - * the type of entity bean to find - * @param uid - * the bean id value - * @param transaction - * the transaction to use (can be null) - */ - public T find(Class beanType, Object uid, Transaction transaction); - - /** - * Insert or update a bean with an explicit transaction. - */ - public void save(Object bean, Transaction transaction) throws OptimisticLockException; - - /** - * Save all the beans in the iterator with an explicit transaction. - */ - public int save(Iterator it, Transaction transaction) throws OptimisticLockException; - - /** - * Save all the beans in the collection with an explicit transaction. - */ - public int save(Collection beans, Transaction transaction) throws OptimisticLockException; - - /** - * Marks the entity bean as dirty. - *

- * This is used so that when a bean that is otherwise unmodified is updated the version - * property is updated. - *

- * An unmodified bean that is saved or updated is normally skipped and this marks the bean as - * dirty so that it is not skipped. - * - *

{@code
-   * 
-   * Customer customer = ebeanServer.find(Customer, id);
-   * 
-   * // mark the bean as dirty so that a save() or update() will
-   * // increment the version property
-   * ebeanServer.markAsDirty(customer);
-   * ebeanServer.save(customer);
-   * 
-   * }
- */ - public void markAsDirty(Object bean); - - /** - * Saves the bean using an update. If you know you are updating a bean then it is preferrable to - * use this update() method rather than save(). - *

- * Stateless updates: Note that the bean does not have to be previously fetched to call - * update().You can create a new instance and set some of its properties programmatically for via - * JSON/XML marshalling etc. This is described as a 'stateless update'. - *

- *

- * Optimistic Locking: Note that if the version property is not set when update() is - * called then no optimistic locking is performed (internally ConcurrencyMode.NONE is used). - *

- *

- * {@link ServerConfig#setUpdatesDeleteMissingChildren(boolean)}: When cascade saving to a - * OneToMany or ManyToMany the updatesDeleteMissingChildren setting controls if any other children - * that are in the database but are not in the collection are deleted. - *

- *

- * {@link ServerConfig#setUpdateChangesOnly(boolean)}: The updateChangesOnly setting - * controls if only the changed properties are included in the update or if all the loaded - * properties are included instead. - *

- * - *
{@code
-   * 
-   * // A 'stateless update' example
-   * Customer customer = new Customer();
-   * customer.setId(7);
-   * customer.setName("ModifiedNameNoOCC");
-   * ebeanServer.update(customer);
-   * 
-   * }
- * - * @see ServerConfig#setUpdatesDeleteMissingChildren(boolean) - * @see ServerConfig#setUpdateChangesOnly(boolean) - */ - public void update(Object bean) throws OptimisticLockException; - - /** - * Update a bean additionally specifying a transaction. - */ - public void update(Object bean, Transaction t) throws OptimisticLockException; - - /** - * Update a bean additionally specifying a transaction and the deleteMissingChildren setting. - * - * @param bean - * the bean to update - * @param transaction - * the transaction to use (can be null). - * @param deleteMissingChildren - * specify false if you do not want 'missing children' of a OneToMany - * or ManyToMany to be automatically deleted. - - */ - public void update(Object bean, Transaction transaction, boolean deleteMissingChildren) throws OptimisticLockException; - - /** - * Update a collection of beans. If there is no current transaction one is created and used to - * update all the beans in the collection. - */ - public void update(Collection beans) throws OptimisticLockException; - - /** - * Update a collection of beans with an explicit transaction. - */ - public void update(Collection beans, Transaction transaction) throws OptimisticLockException; - - /** - * Insert the bean. - *

- * Compared to save() this forces bean to perform an insert rather than trying to decide - * based on the bean state. As such this is useful when you fetch beans from one database - * and want to insert them into another database (and you want to explicitly insert them). - *

- */ - public void insert(Object bean); - - /** - * Insert the bean with a transaction. - */ - public void insert(Object bean, Transaction t); - - /** - * Insert a collection of beans. If there is no current transaction one is created and used to - * insert all the beans in the collection. - */ - public void insert(Collection beans); - - /** - * Insert a collection of beans with an explicit transaction. - */ - public void insert(Collection beans, Transaction t); - - /** - * Delete the associations (from the intersection table) of a ManyToMany given - * the owner bean and the propertyName of the ManyToMany collection. - *

- * Typically these deletions occur automatically when persisting a ManyToMany - * collection and this provides a way to invoke those deletions directly. - *

- * - * @return the number of associations deleted (from the intersection table). - */ - public int deleteManyToManyAssociations(Object ownerBean, String propertyName); - - /** - * Delete the associations (from the intersection table) of a ManyToMany given - * the owner bean and the propertyName of the ManyToMany collection. - *

- * Additionally specify a transaction to use. - *

- *

- * Typically these deletions occur automatically when persisting a ManyToMany - * collection and this provides a way to invoke those deletions directly. - *

- * - * @return the number of associations deleted (from the intersection table). - */ - public int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction t); - - /** - * Save the associations of a ManyToMany given the owner bean and the - * propertyName of the ManyToMany collection. - *

- * Typically the saving of these associations (inserting into the intersection - * table) occurs automatically when persisting a ManyToMany. This provides a - * way to invoke those insertions directly. - *

- */ - public void saveManyToManyAssociations(Object ownerBean, String propertyName); - - /** - * Save the associations of a ManyToMany given the owner bean and the - * propertyName of the ManyToMany collection. - *

- * Typically the saving of these associations (inserting into the intersection - * table) occurs automatically when persisting a ManyToMany. This provides a - * way to invoke those insertions directly. - *

- */ - public void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction t); - - /** - * Save the associated collection or bean given the property name. - *

- * This is similar to performing a save cascade on a specific property - * manually. - *

- *

- * Note that you can turn on/off cascading for a transaction via - * {@link Transaction#setPersistCascade(boolean)} - *

- * - * @param ownerBean - * the bean instance holding the property we want to save - * @param propertyName - * the property we want to save - */ - public void saveAssociation(Object ownerBean, String propertyName); - - /** - * Save the associated collection or bean given the property name with a - * specific transaction. - *

- * This is similar to performing a save cascade on a specific property - * manually. - *

- *

- * Note that you can turn on/off cascading for a transaction via - * {@link Transaction#setPersistCascade(boolean)} - *

- * - * @param ownerBean - * the bean instance holding the property we want to save - * @param propertyName - * the property we want to save - */ - public void saveAssociation(Object ownerBean, String propertyName, Transaction t); - - /** - * Delete the bean with an explicit transaction. - */ - public void delete(Object bean, Transaction t) throws OptimisticLockException; - - /** - * Delete all the beans from an iterator. - */ - public int delete(Iterator it, Transaction t) throws OptimisticLockException; - - /** - * Execute explicitly passing a transaction. - */ - public int execute(SqlUpdate updSql, Transaction t); - - /** - * Execute explicitly passing a transaction. - */ - public int execute(CallableSql callableSql, Transaction t); - - /** - * Execute a TxRunnable in a Transaction with an explicit scope. - *

- * The scope can control the transaction type, isolation and rollback - * semantics. - *

- * - *
{@code
-   *
-   *   // set specific transactional scope settings
-   *   TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
-   *
-   *   ebeanServer.execute(scope, new TxRunnable() {
-   * 	   public void run() {
-   * 		   User u1 = Ebean.find(User.class, 1);
-   * 		   ...
-   * 	   }
-   *   });
-   *
-   * }
- */ - public void execute(TxScope scope, TxRunnable r); - - /** - * Execute a TxRunnable in a Transaction with the default scope. - *

- * The default scope runs with REQUIRED and by default will rollback on any - * exception (checked or runtime). - *

- * - *
{@code
-   *
-   *   ebeanServer.execute(new TxRunnable() {
-   *     public void run() {
-   *       User u1 = ebeanServer.find(User.class, 1);
-   *       User u2 = ebeanServer.find(User.class, 2);
-   *
-   *       u1.setName("u1 mod");
-   *       u2.setName("u2 mod");
-   *
-   *       ebeanServer.save(u1);
-   *       ebeanServer.save(u2);
-   *     }
-   *   });
-   *
-   * }
- */ - public void execute(TxRunnable r); - - /** - * Execute a TxCallable in a Transaction with an explicit scope. - *

- * The scope can control the transaction type, isolation and rollback - * semantics. - *

- * - *
{@code
-   *
-   *   // set specific transactional scope settings
-   *   TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
-   *
-   *   ebeanServer.execute(scope, new TxCallable() {
-   * 	   public String call() {
-   * 		   User u1 = ebeanServer.find(User.class, 1);
-   * 		   ...
-   * 		   return u1.getEmail();
-   * 	   }
-   *   });
-   *
-   * }
- */ - public T execute(TxScope scope, TxCallable c); - - /** - * Execute a TxCallable in a Transaction with the default scope. - *

- * The default scope runs with REQUIRED and by default will rollback on any - * exception (checked or runtime). - *

- *

- * This is basically the same as TxRunnable except that it returns an Object - * (and you specify the return type via generics). - *

- * - *
{@code
-   *
-   *   ebeanServer.execute(new TxCallable() {
-   *     public String call() {
-   *       User u1 = ebeanServer.find(User.class, 1);
-   *       User u2 = ebeanServer.find(User.class, 2);
-   *
-   *       u1.setName("u1 mod");
-   *       u2.setName("u2 mod");
-   *
-   *       ebeanServer.save(u1);
-   *       ebeanServer.save(u2);
-   *
-   *       return u1.getEmail();
-   *     }
-   *   });
-   *
-   * }
- */ - public T execute(TxCallable c); - - /** - * Return the manager of the server cache ("L2" cache). - * - */ - public ServerCacheManager getServerCacheManager(); - - /** - * Return the BackgroundExecutor service for asynchronous processing of - * queries. - */ - public BackgroundExecutor getBackgroundExecutor(); - - /** - * Run the cache warming queries on all bean types that have one defined. - *

- * A cache warming query can be defined via {@link CacheStrategy}. - *

- */ - public void runCacheWarming(); - - /** - * Run the cache warming query for a specific bean type. - *

- * A cache warming query can be defined via {@link CacheStrategy}. - *

- */ - public void runCacheWarming(Class beanType); - - /** - * Return the JsonContext for reading/writing JSON. - * @deprecated Please use #json instead. - */ - public JsonContext createJsonContext(); - - /** - * Return the JsonContext for reading/writing JSON. - *

- * This instance is safe to be used concurrently by multiple threads and this - * method is cheap to call. - *

- * - *

Simple example:

- *
{@code
-   *
-   *     JsonContext json = ebeanServer.json();
-   *     String jsonOutput = json.toJson(list);
-   *     System.out.println(jsonOutput);
-   *
-   * }
- * - *

Using PathProperties:

- *
{@code
-   *
-   *     // specify just the properties we want
-   *     PathProperties paths = PathProperties.parse("name, status, anniversary");
-   *
-   *     List customers =
-   *       ebeanServer.find(Customer.class)
-   *         // apply those paths to the query (only fetch what we need)
-   *         .apply(paths)
-   *         .where().ilike("name", "rob%")
-   *         .findList();
-   *
-   *     // ... get the json
-   *     JsonContext jsonContext = ebeanServer.json();
-   *     String json = jsonContext.toJson(customers, paths);
-   *
-   * }
- * - * @see com.avaje.ebean.text.PathProperties - * @see Query#apply(com.avaje.ebean.text.PathProperties) - */ - public JsonContext json(); - -} +package com.avaje.ebean; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; + +import com.avaje.ebean.annotation.CacheStrategy; +import com.avaje.ebean.cache.ServerCacheManager; +import com.avaje.ebean.config.ServerConfig; +import com.avaje.ebean.meta.MetaInfoManager; +import com.avaje.ebean.text.csv.CsvReader; +import com.avaje.ebean.text.json.JsonContext; + +/** + * Provides the API for fetching and saving beans to a particular DataSource. + *

+ * Registration with the Ebean Singleton:
+ * When a EbeanServer is constructed it can be registered with the Ebean + * singleton (see {@link ServerConfig#setRegister(boolean)}). The Ebean + * singleton is essentially a map of EbeanServer's that have been registered + * with it. The EbeanServer can then be retrieved later via + * {@link Ebean#getServer(String)}. + *

+ *

+ * The 'default' EbeanServer
+ * One EbeanServer can be designated as the 'default' or 'primary' EbeanServer + * (see {@link ServerConfig#setDefaultServer(boolean)}. Many methods on Ebean + * such as {@link Ebean#find(Class)} etc are actually just a convenient way to + * call methods on the 'default/primary' EbeanServer. This is handy for + * applications that use a single DataSource. + *

+ * There is one EbeanServer per Database (javax.sql.DataSource). One EbeanServer + * is referred to as the 'default' server and that is the one that + * Ebean methods such as {@link Ebean#find(Class)} use. + *

+ *

+ * Constructing a EbeanServer
+ * EbeanServer's are constructed by the EbeanServerFactory. They can be created + * programmatically via {@link EbeanServerFactory#create(ServerConfig)} or they + * can be automatically constructed on demand using configuration information in + * the ebean.properties file. + *

+ *

+ * Example: Get a EbeanServer + *

+ * + *
{@code
+ * // Get access to the Human Resources EbeanServer/Database
+ * EbeanServer hrServer = Ebean.getServer("HR");
+ * 
+ * 
+ * // fetch contact 3 from the HR database Contact contact =
+ * hrServer.find(Contact.class, new Integer(3));
+ * 
+ * contact.setStatus("INACTIVE"); ...
+ * 
+ * // save the contact back to the HR database hrServer.save(contact);
+ * }
+ * + *

+ * EbeanServer has more API than Ebean
+ * EbeanServer provides additional API compared with Ebean. For example it + * provides more control over the use of Transactions that is not available in + * the Ebean API. + *

+ *

+ * External Transactions: If you wanted to use transactions created + * externally to eBean then EbeanServer provides additional methods where you + * can explicitly pass a transaction (that can be created externally). + *

+ *

+ * Bypass ThreadLocal Mechanism: If you want to bypass the built in + * ThreadLocal transaction management you can use the createTransaction() + * method. Example: a single thread requires more than one transaction. + *

+ * + * @see Ebean + * @see EbeanServerFactory + * @see ServerConfig + */ +public interface EbeanServer { + + /** + * Shutdown the EbeanServer programmatically. + *

+ * This method is not normally required. Ebean registers a shutdown hook and shuts down cleanly. + *

+ *

+ * If the under underlying DataSource is the Ebean implementation then you + * also have the option of shutting down the DataSource and deregistering the + * JDBC driver. + *

+ * + * @param shutdownDataSource + * if true then shutdown the underlying DataSource if it is the EbeanORM + * DataSource implementation. + * @param deregisterDriver + * if true then deregister the JDBC driver if it is the EbeanORM + * DataSource implementation. + */ + public void shutdown(boolean shutdownDataSource, boolean deregisterDriver); + + /** + * Return the AdminAutofetch which is used to control and configure the + * Autofetch service at runtime. + */ + public AdminAutofetch getAdminAutofetch(); + + /** + * Return the name. This is used with {@link Ebean#getServer(String)} to get a + * EbeanServer that was registered with the Ebean singleton. + */ + public String getName(); + + /** + * Return the ExpressionFactory for this server. + */ + public ExpressionFactory getExpressionFactory(); + + /** + * Return the MetaInfoManager which is used to get meta data from the EbeanServer + * such as query execution statistics. + */ + public MetaInfoManager getMetaInfoManager(); + + /** + * Return the BeanState for a given entity bean. + *

+ * This will return null if the bean is not an enhanced entity bean. + *

+ */ + public BeanState getBeanState(Object bean); + + /** + * Return the value of the Id property for a given bean. + */ + public Object getBeanId(Object bean); + + /** + * Return a map of the differences between two objects of the same type. + *

+ * When null is passed in for b, then the 'OldValues' of a is used for the + * difference comparison. + *

+ */ + public Map diff(Object a, Object b); + + /** + * Create a new instance of T that is an EntityBean. + *

+ * Generally not expected to be useful (now dynamic subclassing support was removed in + * favour of always using enhancement). + *

+ */ + public T createEntityBean(Class type); + + /** + * Create a CsvReader for a given beanType. + */ + public CsvReader createCsvReader(Class beanType); + + /** + * Return a named Query that will have defined fetch paths, predicates etc. + *

+ * The query is created from a statement that will be defined in a deployment + * orm xml file or NamedQuery annotations. The query will typically already + * define fetch paths, predicates, order by clauses etc so often you will just + * need to bind required parameters and then execute the query. + *

+ * + *
{@code
+   *
+   *   // example
+   *   Query query = ebeanServer.createNamedQuery(Order.class, "new.for.customer");
+   *   query.setParameter("customerId", 23);
+   *   List newOrders = query.findList();
+   *
+   * }
+ */ + public Query createNamedQuery(Class beanType, String namedQuery); + + /** + * Create a query using the query language. + *

+ * Note that you are allowed to add additional clauses using where() as well + * as use fetch() and setOrderBy() after the query has been created. + *

+ *

+ * Note that this method signature used to map to named queries and that has + * moved to {@link #createNamedQuery(Class, String)}. + *

+ * + *
{@code
+   *  EbeanServer ebeanServer = ... ;
+   *  String q = "find order fetch details where status = :st";
+   *  
+   *  List newOrders
+   *        = ebeanServer.createQuery(Order.class, q)
+   *             .setParameter("st", Order.Status.NEW)
+   *             .findList();
+   * }
+ * + * @param query + * the object query + */ + public Query createQuery(Class beanType, String query); + + /** + * Create a query for an entity bean and synonym for {@link #find(Class)}. + * + * @see #find(Class) + */ + public Query createQuery(Class beanType); + + /** + * Create a query for a type of entity bean. + *

+ * You can use the methods on the Query object to specify fetch paths, + * predicates, order by, limits etc. + *

+ *

+ * You then use findList(), findSet(), findMap() and findUnique() to execute + * the query and return the collection or bean. + *

+ *

+ * Note that a query executed by {@link Query#findList()} + * {@link Query#findSet()} etc will execute against the same EbeanServer from + * which is was created. + *

+ * + *
{@code
+   *
+   *   // Find order 2 specifying explicitly the parts of the object graph to
+   *   // eagerly fetch. In this case eagerly fetch the associated customer,
+   *   // details and details.product.name
+   *
+   *   Order order = ebeanServer.find(Order.class)
+   *     .fetch("customer")
+   *     .fetch("details")
+   *     .fetch("detail.product", "name")
+   *     .setId(2)
+   *     .findUnique();
+   *
+   *   // find some new orders ... with firstRow/maxRows
+   *   List orders =
+   *     ebeanServer.find(Order.class)
+   *       .where().eq("status", Order.Status.NEW)
+   *       .setFirstRow(20)
+   *       .setMaxRows(10)
+   *       .findList();
+   *
+   * }
+ * + */ + public Query find(Class beanType); + + /** + * Return the next unique identity value for a given bean type. + *

+ * This will only work when a IdGenerator is on the bean such as for beans + * that use a DB sequence or UUID. + *

+ *

+ * For DB's supporting getGeneratedKeys and sequences such as Oracle10 you do + * not need to use this method generally. It is made available for more + * complex cases where it is useful to get an ID prior to some processing. + *

+ */ + public Object nextId(Class beanType); + + /** + * Create a filter for sorting and filtering lists of entities locally without + * going back to the database. + *

+ * This produces and returns a new list with the sort and filters applied. + *

+ *

+ * Refer to {@link Filter} for an example of its use. + *

+ */ + public Filter filter(Class beanType); + + /** + * Sort the list in memory using the sortByClause which can contain a comma delimited + * list of property names and keywords asc, desc, nullsHigh and nullsLow. + *
    + *
  • asc - ascending order (which is the default)
  • + *
  • desc - Descending order
  • + *
  • nullsHigh - Treat null values as high/large values (which is the + * default)
  • + *
  • nullsLow- Treat null values as low/very small values
  • + *
+ *

+ * If you leave off any keywords the defaults are ascending order and treating + * nulls as high values. + *

+ *

+ * Note that the sorting uses a Comparator and Collections.sort(); and does + * not invoke a DB query. + *

+ * + *
{@code
+   *
+   *   // find orders and their customers
+   *   List list = ebeanServer.find(Order.class)
+   *     .fetch("customer")
+   *     .orderBy("id")
+   *     .findList();
+   *
+   *   // sort by customer name ascending, then by order shipDate
+   *   // ... then by the order status descending
+   *   ebeanServer.sort(list, "customer.name, shipDate, status desc");
+   *
+   *   // sort by customer name descending (with nulls low)
+   *   // ... then by the order id
+   *   ebeanServer.sort(list, "customer.name desc nullsLow, id");
+   *
+   * }
+ * + * @param list + * the list of entity beans + * @param sortByClause + * the properties to sort the list by + */ + public void sort(List list, String sortByClause); + + /** + * Create a named orm update. The update statement is specified via the + * NamedUpdate annotation. + *

+ * The orm update differs from the SqlUpdate in that it uses the bean name and + * bean property names rather than table and column names. + *

+ *

+ * Note that named update statements can be specified in raw sql (with column + * and table names) or using bean name and bean property names. This can be + * specified with the isSql flag. + *

+ *

+ * Example named updates: + *

+ * + *
{@code
+   *   package app.data;
+   *
+   *   import ...
+   *
+   *   @NamedUpdates(value = {
+   *    @NamedUpdate( name = "setTitle",
+   * 	    isSql = false,
+   * 		  notifyCache = false,
+   * 		  update = "update topic set title = :title, postCount = :postCount where id = :id"),
+   * 	  @NamedUpdate( name = "setPostCount",
+   * 		  notifyCache = false,
+   * 		  update = "update f_topic set post_count = :postCount where id = :id"),
+   * 	  @NamedUpdate( name = "incrementPostCount",
+   * 		  notifyCache = false,
+   * 		  isSql = false,
+   * 		  update = "update Topic set postCount = postCount + 1 where id = :id") })
+   *   @Entity
+   *   @Table(name = "f_topic")
+   *   public class Topic { ...
+   *
+   * }
+ * + *

+ * Example using a named update: + *

+ * + *
{@code
+   *
+   *   Update update = ebeanServer.createNamedUpdate(Topic.class, "setPostCount");
+   *   update.setParameter("postCount", 10);
+   *   update.setParameter("id", 3);
+   *
+   *   int rows = update.execute();
+   *   System.out.println("rows updated: " + rows);
+   *
+   * }
+ */ + public Update createNamedUpdate(Class beanType, String namedUpdate); + + /** + * Create a orm update where you will supply the insert/update or delete + * statement (rather than using a named one that is already defined using the + * @NamedUpdates annotation). + *

+ * The orm update differs from the sql update in that it you can use the bean + * name and bean property names rather than table and column names. + *

+ *

+ * An example: + *

+ * + *
{@code
+   *
+   *   // The bean name and properties - "topic","postCount" and "id"
+   *
+   *   // will be converted into their associated table and column names
+   *   String updStatement = "update topic set postCount = :pc where id = :id";
+   *
+   *   Update update = ebeanServer.createUpdate(Topic.class, updStatement);
+   *
+   *   update.set("pc", 9);
+   *   update.set("id", 3);
+   *
+   *   int rows = update.execute();
+   *   System.out.println("rows updated:" + rows);
+   *
+   * }
+ */ + public Update createUpdate(Class beanType, String ormUpdate); + + /** + * Create a SqlQuery for executing native sql + * query statements. + *

+ * Note that you can use raw SQL with entity beans, refer to the SqlSelect + * annotation for examples. + *

+ */ + public SqlQuery createSqlQuery(String sql); + + /** + * Create a named sql query. + *

+ * The query statement will be defined in a deployment orm xml file. + *

+ * + * @param namedQuery + * the name of the query + */ + public SqlQuery createNamedSqlQuery(String namedQuery); + + /** + * Create a sql update for executing native dml statements. + *

+ * Use this to execute a Insert Update or Delete statement. The statement will + * be native to the database and contain database table and column names. + *

+ *

+ * See {@link SqlUpdate} for example usage. + *

+ *

+ * Where possible it would be expected practice to put the statement in a orm + * xml file (named update) and use {@link #createNamedSqlUpdate(String)} . + *

+ */ + public SqlUpdate createSqlUpdate(String sql); + + /** + * Create a CallableSql to execute a given stored procedure. + */ + public CallableSql createCallableSql(String callableSql); + + /** + * Create a named sql update. + *

+ * The statement (an Insert Update or Delete statement) will be defined in a + * deployment orm xml file. + *

+ * + *
{@code
+   *
+   *   // Use a namedQuery
+   *   UpdateSql update = Ebean.createNamedSqlUpdate("update.topic.count");
+   *
+   *   update.setParameter("count", 1);
+   *   update.setParameter("topicId", 50);
+   *
+   *   int modifiedCount = update.execute();
+   *
+   * }
+ */ + public SqlUpdate createNamedSqlUpdate(String namedQuery); + + /** + * Register a TransactionCallback on the currently active transaction. + *

+ * If there is no currently active transaction then a PersistenceException is thrown. + * + * @param transactionCallback The transaction callback to be registered with the current transaction. + * + * @throws PersistenceException If there is no currently active transaction + */ + public void register(TransactionCallback transactionCallback) throws PersistenceException; + + /** + * Create a new transaction that is not held in TransactionThreadLocal. + *

+ * You will want to do this if you want multiple Transactions in a single + * thread or generally use transactions outside of the TransactionThreadLocal + * management. + *

+ */ + public Transaction createTransaction(); + + /** + * Create a new transaction additionally specifying the isolation level. + *

+ * Note that this transaction is NOT stored in a thread local. + *

+ */ + public Transaction createTransaction(TxIsolation isolation); + + /** + * Start a new explicit transaction putting it into a ThreadLocal. + *

+ * The transaction is stored in a ThreadLocal variable and typically you only + * need to use the returned Transaction IF you wish to do things like + * use batch mode, change the transaction isolation level, use savepoints or + * log comments to the transaction log. + *

+ *

+ * Example of using a transaction to span multiple calls to find(), save() + * etc. + *

+ * + *
{@code
+   *
+   *    // start a transaction (stored in a ThreadLocal)
+   *    ebeanServer.beginTransaction();
+   *    try {
+   * 	    Order order = ebeanServer.find(Order.class,10);
+   *
+   * 	    ebeanServer.save(order);
+   *
+   * 	    ebeanServer.commitTransaction();
+   *
+   *    } finally {
+   * 	    // rollback if we didn't commit
+   * 	    // i.e. an exception occurred before commitTransaction().
+   * 	    ebeanServer.endTransaction();
+   *    }
+   *
+   * }
+ * + *

Transaction options:

+ *
{@code
+   *
+   *     Transaction txn = ebeanServer.beginTransaction();
+   *     try {
+   *       // explicitly turn on/off JDBC batch use
+   *       txn.setBatchMode(true);
+   *       txn.setBatchSize(50);
+   *
+   *       // control flushing when mixing save and queries
+   *       txn.setBatchFlushOnQuery(false);
+   *
+   *       // turn off persist cascade if needed
+   *       txn.setPersistCascade(false);
+   *
+   *       // for large batch insert processing when we do not
+   *       // ... need the generatedKeys, don't get them
+   *       txn.setBatchGetGeneratedKeys(false);
+   *
+   *       // explicitly flush the JDBC batch buffer
+   *       txn.flushBatch();
+   *
+   *       ...
+   *
+   *       txn.commit();
+   *
+   *    } finally {
+   *       // rollback if necessary
+   *       txn.end();
+   *    }
+   *
+   * }
+ * + *

+ * If you want to externalise the transaction management then you use + * createTransaction() and pass the transaction around to the various methods on + * EbeanServer yourself. + *

+ */ + public Transaction beginTransaction(); + + /** + * Start a transaction additionally specifying the isolation level. + */ + public Transaction beginTransaction(TxIsolation isolation); + + /** + * Returns the current transaction or null if there is no current transaction in scope. + */ + public Transaction currentTransaction(); + + /** + * Commit the current transaction. + */ + public void commitTransaction(); + + /** + * Rollback the current transaction. + */ + public void rollbackTransaction(); + + /** + * If the current transaction has already been committed do nothing otherwise + * rollback the transaction. + *

+ * Useful to put in a finally block to ensure the transaction is ended, rather + * than a rollbackTransaction() in each catch block. + *

+ *

+ * Code example: + * + *

{@code
+   *
+   *   ebeanServer.beginTransaction();
+   *   try {
+   *     // do some fetching and or persisting ...
+   * 
+   *     // commit at the end
+   *     ebeanServer.commitTransaction();
+   * 
+   *   } finally {
+   *     // if commit didn't occur then rollback the transaction
+   *     ebeanServer.endTransaction();
+   *   }
+   *
+   * }
+ * + *

+ * + */ + public void endTransaction(); + + /** + * Refresh the values of a bean. + *

+ * Note that this resets OneToMany and ManyToMany properties so that if they + * are accessed a lazy load will refresh the many property. + *

+ */ + public void refresh(Object bean); + + /** + * Refresh a many property of an entity bean. + * + * @param bean + * the entity bean containing the 'many' property + * @param propertyName + * the 'many' property to be refreshed + * + */ + public void refreshMany(Object bean, String propertyName); + + /** + * Find a bean using its unique id. + * + *
{@code
+   *   // Fetch order 1
+   *   Order order = ebeanServer.find(Order.class, 1);
+   * }
+ * + *

+ * If you want more control over the query then you can use createQuery() and + * Query.findUnique(); + *

+ * + *
{@code
+   *   // ... additionally fetching customer, customer shipping address,
+   *   // order details, and the product associated with each order detail.
+   *   // note: only product id and name is fetch (its a "partial object").
+   *   // note: all other objects use "*" and have all their properties fetched.
+   *
+   *   Query query = ebeanServer.find(Order.class)
+   *     .setId(1)
+   *     .fetch("customer")
+   *     .fetch("customer.shippingAddress")
+   *     .fetch("details")
+   *     .query();
+   *
+   *   // fetch associated products but only fetch their product id and name
+   *   query.fetch("details.product", "name");
+   *
+   *
+   *   Order order = query.findUnique();
+   *
+   *   // traverse the object graph...
+   *
+   *   Customer customer = order.getCustomer();
+   *   Address shippingAddress = customer.getShippingAddress();
+   *   List details = order.getDetails();
+   *   OrderDetail detail0 = details.get(0);
+   *   Product product = detail0.getProduct();
+   *   String productName = product.getName();
+   *
+   * }
+ * + * @param beanType + * the type of entity bean to fetch + * @param id + * the id value + */ + public T find(Class beanType, Object id); + + /** + * Get a reference object. + *

+ * This will not perform a query against the database unless some property other + * that the id property is accessed. + *

+ *

+ * It is most commonly used to set a 'foreign key' on another bean like: + *

+ *
{@code
+   *
+   *   Product product = ebeanServer.getReference(Product.class, 1);
+   *
+   *   OrderDetail orderDetail = new OrderDetail();
+   *   // set the product 'foreign key'
+   *   orderDetail.setProduct(product);
+   *   orderDetail.setQuantity(42);
+   *   ...
+   *
+   *   ebeanServer.save(orderDetail);
+   *
+   *
+   * }
+ * + *

Lazy loading characteristics

+ *
{@code
+   *
+   *   Product product = ebeanServer.getReference(Product.class, 1);
+   *
+   *   // You can get the id without causing a fetch/lazy load
+   *   Long productId = product.getId();
+   *
+   *   // If you try to get any other property a fetch/lazy loading will occur
+   *   // This will cause a query to execute...
+   *   String name = product.getName();
+   *
+   * }
+ * + * @param beanType + * the type of entity bean + * @param id + * the id value + */ + public T getReference(Class beanType, Object id); + + /** + * Return the number of 'top level' or 'root' entities this query should + * return. + * + * @see Query#findRowCount() + * @see com.avaje.ebean.Query#findFutureRowCount() + */ + public int findRowCount(Query query, Transaction transaction); + + /** + * Return the Id values of the query as a List. + * + * @see com.avaje.ebean.Query#findIds() + */ + public List findIds(Query query, Transaction transaction); + + /** + * Return a QueryIterator for the query. + *

+ * Generally using {@link #findEach(Query, QueryEachConsumer, Transaction)} or + * {@link #findEachWhile(Query, QueryEachWhileConsumer, Transaction)} is preferred + * to findIterate(). The reason is that those methods automatically take care of + * closing the queryIterator (and the underlying jdbc statement and resultSet). + *

+ *

+ * This is similar to findEach in that not all the result beans need to be held + * in memory at the same time and as such is good for processing large queries. + *

+ * + * @see Query#findEach(QueryEachConsumer) + * @see Query#findEachWhile(QueryEachWhileConsumer) + */ + public QueryIterator findIterate(Query query, Transaction transaction); + + /** + * Execute the query visiting the each bean one at a time. + *

+ * Unlike findList() this is suitable for processing a query that will return + * a very large resultSet. The reason is that not all the result beans need to be + * held in memory at the same time and instead processed one at a time. + *

+ *

+ * Internally this query using a PersistenceContext scoped to each bean (and the + * beans associated object graph). + *

+ * + *
{@code
+   *
+   *     ebeanServer.find(Order.class)
+   *       .where().eq("status", Order.Status.NEW)
+   *       .order().asc("id")
+   *       .findEach((Order order) -> {
+   *
+   *         // do something with the order bean
+   *         System.out.println(" -- processing order ... " + order);
+   *       });
+   *
+   * }
+ * + * @see Query#findEach(QueryEachConsumer) + * @see Query#findEachWhile(QueryEachWhileConsumer) + */ + public void findEach(Query query, QueryEachConsumer consumer, Transaction transaction); + + /** + * Execute the query visiting the each bean one at a time. + *

+ * Compared to findEach() this provides the ability to stop processing the query + * results early by returning false for the QueryEachWhileConsumer. + *

+ *

+ * Unlike findList() this is suitable for processing a query that will return + * a very large resultSet. The reason is that not all the result beans need to be + * held in memory at the same time and instead processed one at a time. + *

+ *

+ * Internally this query using a PersistenceContext scoped to each bean (and the + * beans associated object graph). + *

+ * + *
{@code
+   *
+   *     ebeanServer.find(Order.class)
+   *       .where().eq("status", Order.Status.NEW)
+   *       .order().asc("id")
+   *       .findEachWhile((Order order) -> {
+   *
+   *         // do something with the order bean
+   *         System.out.println(" -- processing order ... " + order);
+   *
+   *         boolean carryOnProcessing = ...
+   *         return carryOnProcessing;
+   *       });
+   *
+   * }
+ * + * @see Query#findEach(QueryEachConsumer) + * @see Query#findEachWhile(QueryEachWhileConsumer) + */ + public void findEachWhile(Query query, QueryEachWhileConsumer consumer, Transaction transaction); + + /** + * Deprecated in favor of #findEachWhile which is functionally exactly the same + * but has a much better name. + *

+ * Execute the query visiting the results. This is similar to findIterate in + * that not all the result beans need to be held in memory at the same time + * and as such is go for processing large queries. + *

+ * + * @deprecated + */ + public void findVisit(Query query, QueryResultVisitor visitor, Transaction transaction); + + /** + * Execute a query returning a list of beans. + *

+ * Generally you are able to use {@link Query#findList()} rather than + * explicitly calling this method. You could use this method if you wish to + * explicitly control the transaction used for the query. + *

+ * + *
{@code
+   *
+   * List customers =
+   *     ebeanServer.find(Customer.class)
+   *     .where().ilike("name", "rob%")
+   *     .findList();
+   *
+   * }
+ * + * @param + * the type of entity bean to fetch. + * @param query + * the query to execute. + * @param transaction + * the transaction to use (can be null). + * @return the list of fetched beans. + * + * @see Query#findList() + */ + public List findList(Query query, Transaction transaction); + + /** + * Execute find row count query in a background thread. + *

+ * This returns a Future object which can be used to cancel, check the + * execution status (isDone etc) and get the value (with or without a + * timeout). + *

+ * + * @param query + * the query to execute the row count on + * @param transaction + * the transaction (can be null). + * @return a Future object for the row count query + * + * @see com.avaje.ebean.Query#findFutureRowCount() + */ + public FutureRowCount findFutureRowCount(Query query, Transaction transaction); + + /** + * Execute find Id's query in a background thread. + *

+ * This returns a Future object which can be used to cancel, check the + * execution status (isDone etc) and get the value (with or without a + * timeout). + *

+ * + * @param query + * the query to execute the fetch Id's on + * @param transaction + * the transaction (can be null). + * @return a Future object for the list of Id's + * + * @see com.avaje.ebean.Query#findFutureIds() + */ + public FutureIds findFutureIds(Query query, Transaction transaction); + + /** + * Execute find list query in a background thread returning a FutureList object. + *

+ * This returns a Future object which can be used to cancel, check the + * execution status (isDone etc) and get the value (with or without a timeout). + *

+ * This query will execute in it's own PersistenceContext and using its own transaction. + * What that means is that it will not share any bean instances with other queries. + * + * + * @param query + * the query to execute in the background + * @param transaction + * the transaction (can be null). + * @return a Future object for the list result of the query + * + * @see Query#findFutureList() + */ + public FutureList findFutureList(Query query, Transaction transaction); + + /** + * Execute find list SQL query in a background thread. + *

+ * This returns a Future object which can be used to cancel, check the + * execution status (isDone etc) and get the value (with or without a + * timeout). + *

+ * + * @param query + * the query to execute in the background + * @param transaction + * the transaction (can be null). + * @return a Future object for the list result of the query + */ + public SqlFutureList findFutureList(SqlQuery query, Transaction transaction); + + /** + * Return a PagedList for this query. + *

+ * The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and + * {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to + * {@link Query#findFutureRowCount()} to determine total row count, total page count etc. + *

+ *

+ * Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on + * the query. This translates into SQL that uses limit offset, rownum or row_number + * function to limit the result set. + *

+ * + * @param pageIndex + * The zero based index of the page. + * @param pageSize + * The number of beans to return per page. + * @return The PagedList + * + * @see Query#findPagedList(int, int) + */ + public PagedList findPagedList(Query query, Transaction transaction, int pageIndex, int pageSize); + + /** + * Execute the query returning a set of entity beans. + *

+ * Generally you are able to use {@link Query#findSet()} rather than + * explicitly calling this method. You could use this method if you wish to + * explicitly control the transaction used for the query. + *

+ * + *
{@code
+   *
+   * Set customers =
+   *     ebeanServer.find(Customer.class)
+   *     .where().ilike("name", "rob%")
+   *     .findSet();
+   *
+   * }
+ * + * @param + * the type of entity bean to fetch. + * @param query + * the query to execute + * @param transaction + * the transaction to use (can be null). + * @return the set of fetched beans. + * + * @see Query#findSet() + */ + public Set findSet(Query query, Transaction transaction); + + /** + * Execute the query returning the entity beans in a Map. + *

+ * Generally you are able to use {@link Query#findMap()} rather than + * explicitly calling this method. You could use this method if you wish to + * explicitly control the transaction used for the query. + *

+ * + * @param + * the type of entity bean to fetch. + * @param query + * the query to execute. + * @param transaction + * the transaction to use (can be null). + * @return the map of fetched beans. + * + * @see Query#findMap() + */ + public Map findMap(Query query, Transaction transaction); + + /** + * Execute the query returning at most one entity bean. This will throw a + * PersistenceException if the query finds more than one result. + *

+ * Generally you are able to use {@link Query#findUnique()} rather than + * explicitly calling this method. You could use this method if you wish to + * explicitly control the transaction used for the query. + *

+ * + * @param + * the type of entity bean to fetch. + * @param query + * the query to execute. + * @param transaction + * the transaction to use (can be null). + * @return the list of fetched beans. + * + * @see Query#findUnique() + */ + public T findUnique(Query query, Transaction transaction); + + /** + * Execute the sql query returning a list of MapBean. + *

+ * Generally you are able to use {@link SqlQuery#findList()} rather than + * explicitly calling this method. You could use this method if you wish to + * explicitly control the transaction used for the query. + *

+ * + * @param query + * the query to execute. + * @param transaction + * the transaction to use (can be null). + * @return the list of fetched MapBean. + * + * @see SqlQuery#findList() + */ + public List findList(SqlQuery query, Transaction transaction); + + /** + * Execute the sql query returning a set of MapBean. + *

+ * Generally you are able to use {@link SqlQuery#findSet()} rather than + * explicitly calling this method. You could use this method if you wish to + * explicitly control the transaction used for the query. + *

+ * + * @param query + * the query to execute. + * @param transaction + * the transaction to use (can be null). + * @return the set of fetched MapBean. + * + * @see SqlQuery#findSet() + */ + public Set findSet(SqlQuery query, Transaction transaction); + + /** + * Execute the sql query returning a map of MapBean. + *

+ * Generally you are able to use {@link SqlQuery#findMap()} rather than + * explicitly calling this method. You could use this method if you wish to + * explicitly control the transaction used for the query. + *

+ * + * @param query + * the query to execute. + * @param transaction + * the transaction to use (can be null). + * @return the set of fetched MapBean. + * + * @see SqlQuery#findMap() + */ + public Map findMap(SqlQuery query, Transaction transaction); + + /** + * Execute the sql query returning a single MapBean or null. + *

+ * This will throw a PersistenceException if the query found more than one + * result. + *

+ *

+ * Generally you are able to use {@link SqlQuery#findUnique()} rather than + * explicitly calling this method. You could use this method if you wish to + * explicitly control the transaction used for the query. + *

+ * + * @param query + * the query to execute. + * @param transaction + * the transaction to use (can be null). + * @return the fetched MapBean or null if none was found. + * + * @see SqlQuery#findUnique() + */ + public SqlRow findUnique(SqlQuery query, Transaction transaction); + + /** + * Either Insert or Update the bean depending on its state. + *

+ * If there is no current transaction one will be created and committed for + * you automatically. + *

+ *

+ * Save can cascade along relationships. For this to happen you need to + * specify a cascade of CascadeType.ALL or CascadeType.PERSIST on the + * OneToMany, OneToOne or ManyToMany annotation. + *

+ *

+ * In this example below the details property has a CascadeType.ALL set so + * saving an order will also save all its details. + *

+ * + *
{@code
+   *   public class Order { ...
+   *
+   * 	   @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
+   * 	   @JoinColumn(name="order_id")
+   * 	   List details;
+   * 	   ...
+   *   }
+   * }
+ * + *

+ * When a save cascades via a OneToMany or ManyToMany Ebean will automatically + * set the 'parent' object to the 'detail' object. In the example below in + * saving the order and cascade saving the order details the 'parent' order + * will be set against each order detail when it is saved. + *

+ */ + public void save(Object bean) throws OptimisticLockException; + + /** + * Save all the beans in the iterator. + */ + public int save(Iterator it) throws OptimisticLockException; + + /** + * Save all the beans in the collection. + */ + public int save(Collection beans) throws OptimisticLockException; + + /** + * Delete the bean. + *

+ * If there is no current transaction one will be created and committed for + * you automatically. + *

+ */ + public void delete(Object bean) throws OptimisticLockException; + + /** + * Delete all the beans from an Iterator. + */ + public int delete(Iterator it) throws OptimisticLockException; + + /** + * Delete all the beans in the collection. + */ + public int delete(Collection c) throws OptimisticLockException; + + /** + * Delete the bean given its type and id. + */ + public int delete(Class beanType, Object id); + + /** + * Delete the bean given its type and id with an explicit transaction. + */ + public int delete(Class beanType, Object id, Transaction transaction); + + /** + * Delete several beans given their type and id values. + */ + public void delete(Class beanType, Collection ids); + + /** + * Delete several beans given their type and id values with an explicit + * transaction. + */ + public void delete(Class beanType, Collection ids, Transaction transaction); + + /** + * Execute a Sql Update Delete or Insert statement. This returns the number of + * rows that where updated, deleted or inserted. If is executed in batch then + * this returns -1. You can get the actual rowCount after commit() from + * updateSql.getRowCount(). + *

+ * If you wish to execute a Sql Select natively then you should use the + * FindByNativeSql object. + *

+ *

+ * Note that the table modification information is automatically deduced and + * you do not need to call the Ebean.externalModification() method when you + * use this method. + *

+ *

+ * Example: + *

+ * + *
{@code
+   *
+   *   // example that uses 'named' parameters
+   *   String s = "UPDATE f_topic set post_count = :count where id = :id"
+   *
+   *   SqlUpdate update = ebeanServer.createSqlUpdate(s);
+   *
+   *   update.setParameter("id", 1);
+   *   update.setParameter("count", 50);
+   *
+   *   int modifiedCount = ebeanServer.execute(update);
+   *
+   *   String msg = "There where " + modifiedCount + "rows updated";
+   *
+   * }
+ * + * @param sqlUpdate + * the update sql potentially with bind values + * + * @return the number of rows updated or deleted. -1 if executed in batch. + * + * @see CallableSql + */ + public int execute(SqlUpdate sqlUpdate); + + /** + * Execute a ORM insert update or delete statement using the current + * transaction. + *

+ * This returns the number of rows that where inserted, updated or deleted. + *

+ */ + public int execute(Update update); + + /** + * Execute a ORM insert update or delete statement with an explicit + * transaction. + */ + public int execute(Update update, Transaction t); + + /** + * For making calls to stored procedures. + *

+ * Example: + *

+ * + *
{@code
+   *
+   *   String sql = "{call sp_order_modify(?,?,?)}";
+   *
+   *   CallableSql cs = ebeanServer.createCallableSql(sql);
+   *   cs.setParameter(1, 27);
+   *   cs.setParameter(2, "SHIPPED");
+   *   cs.registerOut(3, Types.INTEGER);
+   *
+   *   ebeanServer.execute(cs);
+   *
+   *   // read the out parameter
+   *   Integer returnValue = (Integer) cs.getObject(3);
+   *
+   * }
+ * + * @see CallableSql + * @see Ebean#execute(SqlUpdate) + */ + public int execute(CallableSql callableSql); + + /** + * Inform Ebean that tables have been modified externally. These could be the + * result of from calling a stored procedure, other JDBC calls or external + * programs including other frameworks. + *

+ * If you use ebeanServer.execute(UpdateSql) then the table modification information + * is automatically deduced and you do not need to call this method yourself. + *

+ *

+ * This information is used to invalidate objects out of the cache and + * potentially text indexes. This information is also automatically broadcast + * across the cluster. + *

+ *

+ * If there is a transaction then this information is placed into the current + * transactions event information. When the transaction is committed this + * information is registered (with the transaction manager). If this + * transaction is rolled back then none of the transaction event information + * registers including the information you put in via this method. + *

+ *

+ * If there is NO current transaction when you call this method then this + * information is registered immediately (with the transaction manager). + *

+ * + * @param tableName + * the name of the table that was modified + * @param inserted + * true if rows where inserted into the table + * @param updated + * true if rows on the table where updated + * @param deleted + * true if rows on the table where deleted + */ + public void externalModification(String tableName, boolean inserted, boolean updated, boolean deleted); + + /** + * Find a entity bean with an explicit transaction. + * + * @param + * the type of entity bean to find + * @param beanType + * the type of entity bean to find + * @param uid + * the bean id value + * @param transaction + * the transaction to use (can be null) + */ + public T find(Class beanType, Object uid, Transaction transaction); + + /** + * Insert or update a bean with an explicit transaction. + */ + public void save(Object bean, Transaction transaction) throws OptimisticLockException; + + /** + * Save all the beans in the iterator with an explicit transaction. + */ + public int save(Iterator it, Transaction transaction) throws OptimisticLockException; + + /** + * Save all the beans in the collection with an explicit transaction. + */ + public int save(Collection beans, Transaction transaction) throws OptimisticLockException; + + /** + * Marks the entity bean as dirty. + *

+ * This is used so that when a bean that is otherwise unmodified is updated the version + * property is updated. + *

+ * An unmodified bean that is saved or updated is normally skipped and this marks the bean as + * dirty so that it is not skipped. + * + *

{@code
+   * 
+   * Customer customer = ebeanServer.find(Customer, id);
+   * 
+   * // mark the bean as dirty so that a save() or update() will
+   * // increment the version property
+   * ebeanServer.markAsDirty(customer);
+   * ebeanServer.save(customer);
+   * 
+   * }
+ */ + public void markAsDirty(Object bean); + + /** + * Saves the bean using an update. If you know you are updating a bean then it is preferrable to + * use this update() method rather than save(). + *

+ * Stateless updates: Note that the bean does not have to be previously fetched to call + * update().You can create a new instance and set some of its properties programmatically for via + * JSON/XML marshalling etc. This is described as a 'stateless update'. + *

+ *

+ * Optimistic Locking: Note that if the version property is not set when update() is + * called then no optimistic locking is performed (internally ConcurrencyMode.NONE is used). + *

+ *

+ * {@link ServerConfig#setUpdatesDeleteMissingChildren(boolean)}: When cascade saving to a + * OneToMany or ManyToMany the updatesDeleteMissingChildren setting controls if any other children + * that are in the database but are not in the collection are deleted. + *

+ *

+ * {@link ServerConfig#setUpdateChangesOnly(boolean)}: The updateChangesOnly setting + * controls if only the changed properties are included in the update or if all the loaded + * properties are included instead. + *

+ * + *
{@code
+   * 
+   * // A 'stateless update' example
+   * Customer customer = new Customer();
+   * customer.setId(7);
+   * customer.setName("ModifiedNameNoOCC");
+   * ebeanServer.update(customer);
+   * 
+   * }
+ * + * @see ServerConfig#setUpdatesDeleteMissingChildren(boolean) + * @see ServerConfig#setUpdateChangesOnly(boolean) + */ + public void update(Object bean) throws OptimisticLockException; + + /** + * Update a bean additionally specifying a transaction. + */ + public void update(Object bean, Transaction t) throws OptimisticLockException; + + /** + * Update a bean additionally specifying a transaction and the deleteMissingChildren setting. + * + * @param bean + * the bean to update + * @param transaction + * the transaction to use (can be null). + * @param deleteMissingChildren + * specify false if you do not want 'missing children' of a OneToMany + * or ManyToMany to be automatically deleted. + + */ + public void update(Object bean, Transaction transaction, boolean deleteMissingChildren) throws OptimisticLockException; + + /** + * Update a collection of beans. If there is no current transaction one is created and used to + * update all the beans in the collection. + */ + public void update(Collection beans) throws OptimisticLockException; + + /** + * Update a collection of beans with an explicit transaction. + */ + public void update(Collection beans, Transaction transaction) throws OptimisticLockException; + + /** + * Insert the bean. + *

+ * Compared to save() this forces bean to perform an insert rather than trying to decide + * based on the bean state. As such this is useful when you fetch beans from one database + * and want to insert them into another database (and you want to explicitly insert them). + *

+ */ + public void insert(Object bean); + + /** + * Insert the bean with a transaction. + */ + public void insert(Object bean, Transaction t); + + /** + * Insert a collection of beans. If there is no current transaction one is created and used to + * insert all the beans in the collection. + */ + public void insert(Collection beans); + + /** + * Insert a collection of beans with an explicit transaction. + */ + public void insert(Collection beans, Transaction t); + + /** + * Delete the associations (from the intersection table) of a ManyToMany given + * the owner bean and the propertyName of the ManyToMany collection. + *

+ * Typically these deletions occur automatically when persisting a ManyToMany + * collection and this provides a way to invoke those deletions directly. + *

+ * + * @return the number of associations deleted (from the intersection table). + */ + public int deleteManyToManyAssociations(Object ownerBean, String propertyName); + + /** + * Delete the associations (from the intersection table) of a ManyToMany given + * the owner bean and the propertyName of the ManyToMany collection. + *

+ * Additionally specify a transaction to use. + *

+ *

+ * Typically these deletions occur automatically when persisting a ManyToMany + * collection and this provides a way to invoke those deletions directly. + *

+ * + * @return the number of associations deleted (from the intersection table). + */ + public int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction t); + + /** + * Save the associations of a ManyToMany given the owner bean and the + * propertyName of the ManyToMany collection. + *

+ * Typically the saving of these associations (inserting into the intersection + * table) occurs automatically when persisting a ManyToMany. This provides a + * way to invoke those insertions directly. + *

+ */ + public void saveManyToManyAssociations(Object ownerBean, String propertyName); + + /** + * Save the associations of a ManyToMany given the owner bean and the + * propertyName of the ManyToMany collection. + *

+ * Typically the saving of these associations (inserting into the intersection + * table) occurs automatically when persisting a ManyToMany. This provides a + * way to invoke those insertions directly. + *

+ */ + public void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction t); + + /** + * Save the associated collection or bean given the property name. + *

+ * This is similar to performing a save cascade on a specific property + * manually. + *

+ *

+ * Note that you can turn on/off cascading for a transaction via + * {@link Transaction#setPersistCascade(boolean)} + *

+ * + * @param ownerBean + * the bean instance holding the property we want to save + * @param propertyName + * the property we want to save + */ + public void saveAssociation(Object ownerBean, String propertyName); + + /** + * Save the associated collection or bean given the property name with a + * specific transaction. + *

+ * This is similar to performing a save cascade on a specific property + * manually. + *

+ *

+ * Note that you can turn on/off cascading for a transaction via + * {@link Transaction#setPersistCascade(boolean)} + *

+ * + * @param ownerBean + * the bean instance holding the property we want to save + * @param propertyName + * the property we want to save + */ + public void saveAssociation(Object ownerBean, String propertyName, Transaction t); + + /** + * Delete the bean with an explicit transaction. + */ + public void delete(Object bean, Transaction t) throws OptimisticLockException; + + /** + * Delete all the beans from an iterator. + */ + public int delete(Iterator it, Transaction t) throws OptimisticLockException; + + /** + * Execute explicitly passing a transaction. + */ + public int execute(SqlUpdate updSql, Transaction t); + + /** + * Execute explicitly passing a transaction. + */ + public int execute(CallableSql callableSql, Transaction t); + + /** + * Execute a TxRunnable in a Transaction with an explicit scope. + *

+ * The scope can control the transaction type, isolation and rollback + * semantics. + *

+ * + *
{@code
+   *
+   *   // set specific transactional scope settings
+   *   TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
+   *
+   *   ebeanServer.execute(scope, new TxRunnable() {
+   * 	   public void run() {
+   * 		   User u1 = Ebean.find(User.class, 1);
+   * 		   ...
+   * 	   }
+   *   });
+   *
+   * }
+ */ + public void execute(TxScope scope, TxRunnable r); + + /** + * Execute a TxRunnable in a Transaction with the default scope. + *

+ * The default scope runs with REQUIRED and by default will rollback on any + * exception (checked or runtime). + *

+ * + *
{@code
+   *
+   *    ebeanServer.execute(new TxRunnable() {
+   *      public void run() {
+   *        User u1 = ebeanServer.find(User.class, 1);
+   *        User u2 = ebeanServer.find(User.class, 2);
+   *
+   *        u1.setName("u1 mod");
+   *        u2.setName("u2 mod");
+   *
+   *        ebeanServer.save(u1);
+   *        ebeanServer.save(u2);
+   *      }
+   *    });
+   *
+   * }
+ */ + public void execute(TxRunnable r); + + /** + * Execute a TxCallable in a Transaction with an explicit scope. + *

+ * The scope can control the transaction type, isolation and rollback + * semantics. + *

+ * + *
{@code
+   *
+   *   // set specific transactional scope settings
+   *   TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
+   *
+   *   ebeanServer.execute(scope, new TxCallable() {
+   * 	   public String call() {
+   * 		   User u1 = ebeanServer.find(User.class, 1);
+   * 		   ...
+   * 		   return u1.getEmail();
+   * 	   }
+   *   });
+   *
+   * }
+ */ + public T execute(TxScope scope, TxCallable c); + + /** + * Execute a TxCallable in a Transaction with the default scope. + *

+ * The default scope runs with REQUIRED and by default will rollback on any + * exception (checked or runtime). + *

+ *

+ * This is basically the same as TxRunnable except that it returns an Object + * (and you specify the return type via generics). + *

+ * + *
{@code
+   *
+   *   ebeanServer.execute(new TxCallable() {
+   *     public String call() {
+   *       User u1 = ebeanServer.find(User.class, 1);
+   *       User u2 = ebeanServer.find(User.class, 2);
+   *
+   *       u1.setName("u1 mod");
+   *       u2.setName("u2 mod");
+   *
+   *       ebeanServer.save(u1);
+   *       ebeanServer.save(u2);
+   *
+   *       return u1.getEmail();
+   *     }
+   *   });
+   *
+   * }
+ */ + public T execute(TxCallable c); + + /** + * Return the manager of the server cache ("L2" cache). + * + */ + public ServerCacheManager getServerCacheManager(); + + /** + * Return the BackgroundExecutor service for asynchronous processing of + * queries. + */ + public BackgroundExecutor getBackgroundExecutor(); + + /** + * Run the cache warming queries on all bean types that have one defined. + *

+ * A cache warming query can be defined via {@link CacheStrategy}. + *

+ */ + public void runCacheWarming(); + + /** + * Run the cache warming query for a specific bean type. + *

+ * A cache warming query can be defined via {@link CacheStrategy}. + *

+ */ + public void runCacheWarming(Class beanType); + + /** + * Return the JsonContext for reading/writing JSON. + * @deprecated Please use #json instead. + */ + public JsonContext createJsonContext(); + + /** + * Return the JsonContext for reading/writing JSON. + *

+ * This instance is safe to be used concurrently by multiple threads and this + * method is cheap to call. + *

+ * + *

Simple example:

+ *
{@code
+   *
+   *     JsonContext json = ebeanServer.json();
+   *     String jsonOutput = json.toJson(list);
+   *     System.out.println(jsonOutput);
+   *
+   * }
+ * + *

Using PathProperties:

+ *
{@code
+   *
+   *     // specify just the properties we want
+   *     PathProperties paths = PathProperties.parse("name, status, anniversary");
+   *
+   *     List customers =
+   *       ebeanServer.find(Customer.class)
+   *         // apply those paths to the query (only fetch what we need)
+   *         .apply(paths)
+   *         .where().ilike("name", "rob%")
+   *         .findList();
+   *
+   *     // ... get the json
+   *     JsonContext jsonContext = ebeanServer.json();
+   *     String json = jsonContext.toJson(customers, paths);
+   *
+   * }
+ * + * @see com.avaje.ebean.text.PathProperties + * @see Query#apply(com.avaje.ebean.text.PathProperties) + */ + public JsonContext json(); + +} diff --git a/src/main/java/com/avaje/ebean/annotation/Transactional.java b/src/main/java/com/avaje/ebean/annotation/Transactional.java index 33c7851c3..a27b80fe4 100644 --- a/src/main/java/com/avaje/ebean/annotation/Transactional.java +++ b/src/main/java/com/avaje/ebean/annotation/Transactional.java @@ -1,103 +1,104 @@ -package com.avaje.ebean.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.avaje.ebean.TxIsolation; -import com.avaje.ebean.TxType; - -/** - * Specify transaction scoping for a method. - *

- * This is only supported if "Enhancement" is used via javaagent, ANT - * task or IDE enhancement plugin etc. - *

- *

- * Note: Currently there are 3 known annotations that perform this role. - *

    - *
  • EJB's javax.ejb.TransactionAttribute
  • - *
  • Spring's org.springframework.transaction.annotation.Transactional
  • - *
  • and this one, Ebean's own com.avaje.ebean.annotation.Transactional
  • - *
- * Spring created their one because the EJB annotation does not support features - * such as isolation level and specifying rollbackOn, noRollbackOn exceptions. - * This one exists for Ebean because I agree that the standard one is - * insufficient and don't want to include a dependency on Spring. - *

- *

- * The default behaviour of EJB (and hence Spring) is to NOT ROLLBACK on checked - * exceptions. I find this very counter-intuitive. Ebean will provide a property - * to set the default behaviour to rollback on any exception and optionally - * change the setting to be consistent with EJB/Spring if people wish to do so. - *

- * - *
- * 
- *  // a normal class
- * public class MySimpleUserService {
- * 
- *  // this method is transactional automatically handling 
- *  // transaction begin, commit and rollback etc
- *  @Transactional
- *  public void runInTrans() throws IOException {
- * 
- *    // tasks performed within the transaction
- *    ...
- *    // find some objects
- *    Customer cust = Ebean.find(Customer.class, 1);
- *    
- *    Order order = ...;
- *    ...
- *    // save some objects
- *    Ebean.save(customer);
- *    Ebean.save(order);
- *  }
- * 
- */ -@Target({ ElementType.METHOD, ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface Transactional { - - /** - * The type of transaction scoping. Defaults to REQUIRED. - */ - TxType type() default TxType.REQUIRED; - - /** - * The transaction isolation level this transaction should have. - *

- * This will only be used if this scope creates the transaction. If the - * transaction has already started then this will currently be ignored (you - * could argue that it should throw an exception). - *

- */ - TxIsolation isolation() default TxIsolation.DEFAULT; - - /** - * Set this to true if the transaction should be only contain queries. - */ - boolean readOnly() default false; - - /** - * The name of the server that you want the transaction to be created from. - *

- * If left blank the 'default' server is used. - *

- */ - String serverName() default ""; - - // int timeout() default 0; - - /** - * The throwable's that will explicitly cause a rollback to occur. - */ - Class[] rollbackFor() default {}; - - /** - * The throwable's that will explicitly NOT cause a rollback to occur. - */ - Class[] noRollbackFor() default {}; - -}; +package com.avaje.ebean.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.avaje.ebean.TxIsolation; +import com.avaje.ebean.TxType; + +/** + * Specify transaction scoping for a method. + *

+ * This is only supported if "Enhancement" is used via javaagent, ANT + * task or IDE enhancement plugin etc. + *

+ *

+ * Note: Currently there are 3 known annotations that perform this role. + *

    + *
  • EJB's javax.ejb.TransactionAttribute
  • + *
  • Spring's org.springframework.transaction.annotation.Transactional
  • + *
  • and this one, Ebean's own com.avaje.ebean.annotation.Transactional
  • + *
+ * Spring created their one because the EJB annotation does not support features + * such as isolation level and specifying rollbackOn, noRollbackOn exceptions. + * This one exists for Ebean because I agree that the standard one is + * insufficient and don't want to include a dependency on Spring. + *

+ *

+ * The default behaviour of EJB (and hence Spring) is to NOT ROLLBACK on checked + * exceptions. I find this very counter-intuitive. Ebean will provide a property + * to set the default behaviour to rollback on any exception and optionally + * change the setting to be consistent with EJB/Spring if people wish to do so. + *

+ * + *
{@code
+ *
+ *  // a normal class
+ *  public class MySimpleUserService {
+ * 
+ *    // this method is transactional automatically handling
+ *    // transaction begin, commit and rollback etc
+ *    @Transactional
+ *    public void runInTrans() throws IOException {
+ * 
+ *      // tasks performed within the transaction
+ *      ...
+ *      // find some objects
+ *      Customer cust = ebeanServer.find(Customer.class, 42);
+ *    
+ *      Order order = ...;
+ *      ...
+ *      // save some objects
+ *      ebeanServer.save(customer);
+ *      ebeanServer.save(order);
+ *    }
+ *
+ * }
+ */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Transactional { + + /** + * The type of transaction scoping. Defaults to REQUIRED. + */ + TxType type() default TxType.REQUIRED; + + /** + * The transaction isolation level this transaction should have. + *

+ * This will only be used if this scope creates the transaction. If the + * transaction has already started then this will currently be ignored (you + * could argue that it should throw an exception). + *

+ */ + TxIsolation isolation() default TxIsolation.DEFAULT; + + /** + * Set this to true if the transaction should be only contain queries. + */ + boolean readOnly() default false; + + /** + * The name of the server that you want the transaction to be created from. + *

+ * If left blank the 'default' server is used. + *

+ */ + String serverName() default ""; + + // int timeout() default 0; + + /** + * The Throwable's that will explicitly cause a rollback to occur. + */ + Class[] rollbackFor() default {}; + + /** + * The Throwable's that will explicitly NOT cause a rollback to occur. + */ + Class[] noRollbackFor() default {}; + +};