باستخدام حامل المفاتيح في الربيع مع المفاتيح الأولية التي تم إنشاؤها برمجيًا

StackOverflow https://stackoverflow.com/questions/2819514

سؤال

أنا أستخدم namedparameterjdbctemplate من الربيع لأداء إدراج في جدول. يستخدم الجدول NextVal على تسلسل للحصول على المفتاح الأساسي. ثم أريد أن يتم نقل هذا المعرف الذي تم إنشاؤه إلي. أنا أستخدم تطبيق حامل المفاتيح في الربيع مثل هذا:

KeyHolder key = new GeneratedKeyHolder();
jdbcTemplate.update(Constants.INSERT_ORDER_STATEMENT, params, key);

ومع ذلك ، عندما أقوم بتشغيل هذا البيان ، أحصل على:

org.springframework.dao.DataRetrievalFailureException: The generated key is not of a supported numeric type. Unable to cast [oracle.sql.ROWID] to [java.lang.Number]
    at org.springframework.jdbc.support.GeneratedKeyHolder.getKey(GeneratedKeyHolder.java:73)

أي أفكار ما أفتقده؟

هل كانت مفيدة؟

المحلول

أعتقد أنك تستخدم الطريقة الخاطئة JdbcTemplate. الوحيد من update الطرق التي يبدو أنها تتطابق مع جزء الكود الخاص بك

int update(String sql, Object... args)

إذا كان الأمر كذلك ، فأنت تمر params و key كصفيف Vargs ثنائي العناصر ، و JdbcTemplate يعالج key كمعلمات ربط طبيعية ، وسوء تفسيرها.

الجمهور الوحيد update طريقة على JdbcTemplate هذا يأخذ KeyHolder هو

int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)

لذلك ستحتاج إلى إعادة صياغة الكود الخاص بك لاستخدام ذلك.

نصائح أخرى

فقط حل مشكلة مماثلة - مع Oracle تحتاج إلى استخدام طريقة أخرى (من NamedParameterJdbcOperations) -

int update(String sql,
           SqlParameterSource paramSource,
           KeyHolder generatedKeyHolder,
           String[] keyColumnNames)
           throws DataAccessException

مع keycolumnnames تحتوي على أعمدة تم إنشاؤها تلقائيًا ، في حالتي فقط ["id"]. وإلا فإن كل ما تحصل عليه هو رويد. نرى وثيقة الربيع للتفاصيل.

عليك تنفيذ JdbcTemplate.update(PreparedStatementCreator p, KeyHolder k).

سيتم حقن المفتاح الذي تم إرجاعه من قاعدة البيانات في KeyHolder كائن المعلمة.

مثال:

final String INSERT_ORDER_STATEMENT 
       = "insert into order (product_id, quantity) values(?, ?)";

KeyHolder keyHolder = new GeneratedKeyHolder();
    jdbcTemplate.update(new PreparedStatementCreator() {
        public PreparedStatement createPreparedStatement(
            Connection connection) throws SQLException {
                PreparedStatement ps = connection.prepareStatement(
                    INSERT_ORDER_STATEMENT, new String[] { "id" });
                ps.setInt(1, order.getProductId());
                ps.setInt(2, order.getQuantity());
                return ps;
            }
        }, keyHolder);

يمكن العثور على مزيد من المعلومات هنا في الوثائق المرجعية.

لا يوجد تفصيلي على konstantin الإجابة: إليك مثال يعمل تمامًا: على افتراض أن قاعدة البيانات هي Oracle و Column Name التي يتم إنشاؤها معرف المتجر "enderated_id" (يمكن أن يكون أي اسم). ملاحظة: لقد استخدمت namedparameterjdbctemplate.update (....) في هذا المثال ، فئة JDBCtemplate من الربيع.

       public Integer insertRecordReturnGeneratedId(final MyObject obj)
            {
            final String INSERT_QUERY = "INSERT INTO MY_TABLE  VALUES(GENERATED_ID_SEQ.NEXTVAL, :param1, :param2)";
            try
                {
                    MapSqlParameterSource parameters = new MapSqlParameterSource().addValue( "param1", obj.getField1() ).addValue( "param2",  obj.getField1() ) ;
                    final KeyHolder holder = new GeneratedKeyHolder();
                    this.namedParameterJdbcTemplate.update( INSERT_QUERY, parameters, holder, new String[] {"GENERATED_ID" } );
                    Number generatedId = holder.getKey();
                   // Note: USING holder.getKey("GENERATED_ID") IS ok TOO.
                    return generatedId.intValue();
                }
                catch( DataAccessException dataAccessException )
                {
        }
        }

مع MySQL

CREATE TABLE `vets` (
  `id` int(4) unsigned NOT NULL AUTO_INCREMENT,
  `first_name` varchar(30) DEFAULT NULL,
  `last_name` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `last_name` (`last_name`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;


public @Data class Vet {
    private int id;
    private String firstname;
    private String lastname;
}

@Repository
public class VetDaoImpl implements VetDao {
/** Logger. */
private static final Logger LOGGER = LoggerFactory.getLogger(VetDaoImpl.class);

private static final String INSERT_VET = "INSERT INTO vets (first_name, last_name) VALUES (:first_name, :last_name)";

@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

@Override
public Number insertVet(final Vet vet) {
    MapSqlParameterSource paramSource = new MapSqlParameterSource();
    paramSource.addValue("first_name", vet.getFirstname());
    paramSource.addValue("last_name", vet.getLastname());
    KeyHolder keyHolder = new GeneratedKeyHolder();
    int nbRecord = namedParameterJdbcTemplate.update(INSERT_VET, paramSource, keyHolder, new String[] {"id" });
    LOGGER.info("insertVet: id ["+keyHolder.getKey()+"]");
    return nbRecord;
}
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top